原标题: GraalVM - an introduction to the next level JVM
随着 Red Hat 宣布 Quarkus 作为...
为 GraalVM 和 HotSpot 量身定制的下一代 Kubernetes 原生 Java 框架, 使用一流的 Java 库和标准构建
https://quarkus.io/
Red Hat 展示的 Quarkus 示例项目 https://quarkus.io/ 的启动速度和内存消耗给我留下了深刻的印象. 令人印象深刻的主要原因之一是, 代码是用 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 https://openjdk.java.net/jeps/295 ,JDK 获得了提前 (ahead-of-time,AOT) 编译器 jaotc. 该编译器使用 OpenJDK 项目 Graal https://openjdk.java.net/projects/graal/ 进行后端代码生成, 这样做的原因如下:
JIT 编译器速度很快, 但是 Java 程序可能非常庞大, 以至于 JIT 完全预热需要很长时间. 很少使用的 Java 方法可能根本不会被编译, 由于重复的解释调用可能会导致性能下降
https://openjdk.java.net/jeps/295
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 个内核) 进行尝试.
来源: https://www.cnblogs.com/dongxishaonian/p/13326310.html