【譯】GraalVM—下一代JVM介紹
原標題: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相比,生成的程式具有更快的啟動時間和更低的運行時記憶體開銷。
使用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個內核)進行嘗試。
原文地址://rieckpil.de/whatis-graalvm/
🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟
歡迎訪問筆者部落格:blog.dongxishaonian.tech
關注筆者公眾號,推送各類原創/優質技術文章 ⬇️