原標題:GraalVM – an introduction to the next level JVM
隨着Red Hat宣布Quarkus作為…
為GraalVM和HotSpot量身定制的下一代Kubernetes原生Java框架,使用一流的Java庫和標准構建
Red Hat展示的Quarkus示例項目的啟動速度和內存消耗給我留下了深刻的印象。令人印象深刻的主要原因之一是,代碼是用GraalVM提前(ahead-of-time,AOT)編譯成本機映像(native image)的。為了幫助您更好地了解傳統的HotSpot JVM和GraalVM之間的區別,我將在此博客文章中向您介紹GraalVM及其功能和歷史。
TL; DR:GraalVM是Oracle開發的用純Java編寫的JVM擴展,支持多語言編程和提前編譯。
HotSpot Java虛擬機的歷史
多年來,HotSpot是Oracle維護和分發的主要Java虛擬機,用於運行Java程序。 Java HotSpot Performance Engine於1999年發布,最初由Animorphic開發,該公司被Sun Microsystems收購,現在由Oracle擁有。該虛擬機主要用C / C ++編寫,並且變得越來越復雜(2007年估計有250.000行代碼)。
HotSpot JVM的主要目的是運行Java字節碼(.class文件)並持續分析程序的性能,以查找程序中經常執行的所謂熱點,並即時(JIT,全稱just-in-time)將其編譯為本機代碼(機器代碼)以提高性能。這是在運行時完成的,而不是在Java程序執行之前執行的,因此是即時(just-in-time)的。
在HotSpot JVM中運行Java代碼的工作流程如下所示(簡化):
HotSpot虛擬機主要解釋程序提供的Java字節碼,但在程序運行過程中發現有適合優化的部分時,也會及時將這部分字節碼編譯為機器代碼。
當使用JIT編譯器編譯一個方法時,當該方法被調用時,jvm將直接執行編譯出來的機器碼,而不是解釋它以此來提高性能。由於編譯本機代碼需要CPU時間和內存,JVM必須在運行時決定編譯哪些方法,因為將所有方法直接編譯為本機代碼會影響性能。
Java 9發行版中的更改
借助Java 9,特別是JEP 295,JDK獲得了提前(ahead-of-time,AOT)編譯器jaotc。該編譯器使用OpenJDK項目Graal進行后端代碼生成,這樣做的原因如下:
JIT編譯器速度很快,但是Java程序可能非常龐大,以至於JIT完全預熱需要很長時間。很少使用的Java方法可能根本不會被編譯,由於重復的解釋調用可能會導致性能下降
Graal OpenJDK項目演示了用純Java編寫的編譯器可以生成高度優化的代碼。使用此AOT編譯器和Java 9,您可以提前手動編譯Java代碼。這意味着在執行之前生成機器代碼,而不是像JIT編譯器那樣在運行時生成代碼,這是第一種實驗性的方法。
# using the new AOT compiler (jaotc is bundeled within JDK 9 and above)
jaotc --output libHelloWorld.so HelloWorld.class
jaotc --output libjava.base.so --module java.base
# with Java 9 you have to manually specify the location of the native code
java -XX:AOTLibrary=./libHelloWorld.so,./libjava.base.so HelloWorld
這將改善啟動時間,因為JIT編譯器不必攔截程序的執行。這種方法的主要缺點是生成的機器代碼依賴於程序所在的平台(Linux,MacOS,windows...)。這可能導致AOT編譯代碼與特定平台綁定。
GraalVM的架構
基於Graal編譯器,Oracle開始開發GraalVM,不僅與HotSpots JVM的復雜C/C++代碼庫一起工作,而且還可以通過用Java編寫的虛擬機解決當前的多語言遷移問題。
GraalVM的架構如下所示:
首先,您可能會注意到一些非JVM語言的存在。現在可以在這個通用虛擬機中運行Ruby、R或JavaScript代碼。只是因為GraalVM采用了Truffle框架。Truffle是一個開源庫,用於構建編程語言實現,作為自修改(self-modifying)抽象語法樹的解釋器。有了這個特性,您現在可以在Java代碼庫中編寫和執行例如JavaScript代碼。
此外,GraalVM提供了以下功能,可以提前將程序編譯成本機可執行文件:
GraalVM允許您提前將程序編譯為本地可執行文件。生成的程序不能在Java HotSpot VM上運行,而是使用必要的組件,例如內存管理,來自另一種虛擬機實現的線程調度(稱為Substrate VM)。SubstrateVM用Java編寫,然后編譯進本地可執行文件。與Java VM相比,生成的程序具有更快的啟動時間和更低的運行時內存開銷。
https://www.graalvm.org/docs/reference-manual/aot-compilation/
使用GraalVM編譯並運行第一個Java程序
撰寫本文時,GraalVM有兩個版本:社區版(CE)和企業版(EE),僅適用於Mac OS X和Linux。要在開發過程中在Windows上使用GraalVM,您可以使用Oracle的官方Docker映像,以下示例中使用了該映像。
想象下面的簡單HelloWorld類:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
在GraalVM和Java 9的AOT編譯器之前,您執行了如下代碼:
$ javac HelloWorld.java
$ java HelloWorld
Hello World!
借助GraalVM,您現在可以選擇使用現有方式(HotSpot JVM)運行應用程序,或者使用GraalVM AOT編譯器創建本機映像並運行可執行文件:
$ javac HelloWorld
$ native-image HelloWorld
$ ./helloworld
HelloWorld!
在這個HelloWorld示例中,改進的性能是微不足道的,但是在更大和更現實的應用程序中,性能的改進是顯著的。
在官方的GraalVM入門指南中可以找到一個簡單的多語言應用程序示例:
import java.io.*;
import java.util.stream.*;
import org.graalvm.polyglot.*;
public class PrettyPrintJSON {
public static void main(String[] args) throws java.io.IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String input = reader.lines().collect(Collectors.joining(System.lineSeparator()));
try (Context context = Context.create("js")) {
Value parse = context.eval("js", "JSON.parse");
Value stringify = context.eval("js", "JSON.stringify");
Value result = stringify.execute(parse.execute(input));
System.out.println(result.asString());
}
}
}
這個Java類負責漂亮地打印JSON,使用JavaScript方法JSON.parse() 和JSON.stringify() 。此類的本機鏡像可通過如下方式構建:
$ javac PrettyPrintJSON.java
$ native-image --language:js PrettyPrintJSON
$ ./prettyprintjson < prettyMe.json
{
"GraalVM": {
"description": "Language Abstraction Platform",
"supports": [
"combining languages",
"embedding languages",
"creating native images"
],
"languages": [
"Java",
"JavaScript",
"Node.js",
"Python",
"Ruby",
"R",
"LLVM"
]
}
}
現在可以測量運行本機映像和在HotSpot中運行應用程序之間的性能差異:
$ time bin/java PrettyPrintJSON < prettyMe.json > /dev/null
real 0m1.101s
user 0m2.471s
sys 0m0.237s
$ time ./prettyprintjson < prettyMe.json > /dev/null
real 0m0.037s
user 0m0.015s
sys 0m0.016s
在我看來,Oracle和GraalVM在Java作為編程語言的主導地位方面做得非常好。此外,這一舉措提高了Java語言本身的可持續性和特性開發。有了多語言體系結構,這也增加了其他編程語言的采用。
您可以在我的GitHub存儲庫中找到示例,然后直接在GraalVM上(Mac和Linux)或在Windows上的Docker上(確保為Docker提供至少6 GB的RAM和2-4個內核)進行嘗試。
原文地址:https://rieckpil.de/whatis-graalvm/
🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟
歡迎訪問筆者博客:blog.dongxishaonian.tech
關注筆者公眾號,推送各類原創/優質技術文章 ⬇️