查看原文
其他

一文了解GraalVM

ImportNew 2022-10-28

The following article is from 古古说 Author 古古

(给ImportNew加星标,提高Java技能)

来源:古古说(本文来自作者投稿)


GraalVM 是 Oracle 发布的下一代 Java 虚拟机,2019年5月 才发布了第一个 Release 版本,提供社区版和企业版。


GraalVM 三大特点


1. 高效运行 Java


使用 GraalVM 执行 Java 程序速度更快。

2. 多语言并行


可以在 Java 里面同时使用多种语言,像是 JavaScript、R 等等。

3. 快速启动


直接把 Java 应用编译成机器码,执行起来体积更小、启动速度更快。


1. 高效能运行 Java


GraalVM 之所以能够更高效能运行 Java 应用,是因为使用到了 Graal 编译器技术,而 Graal 编译器是一个 JIT 编译器,但什么又是 JIT 编译器呢?


实际上,在 Java 里的编译期可以分为前端编译器和运行期编译器,前端编译器是指将 .java 编译成 .class 的过程,而运行期编译器则是指将 .class 字节码转变成机器码的过程,而运行期编译器的英文为 Just In Time Compiler,所以又简称为 JIT 编译器。


当初 JVM 开发团队把大部分的代码优化都放在运行期的编译器 JIT 上,而前端的编译器 javac 几乎没有任何代码优化措施,原因是因为这样可以让那些不是由 javac 产生的 .class 文件,也能享受到编译器优化所带来的好处,而前端编译器 javac 则专门负责处理 Java 的语法糖,将他转换为正常的字节码,因此可以说前端编译器 javac 是负责增进程序员开发效率,而运行其编译器 JIT 则是负责增进代码运行速度。


  • 前端编译器 javac : 负责将 Java 中的语法糖转换为正常的字节码;
  • 运行期编译器 JIT : 负责代码优化。



了解了 JIT 编译器之后,我们说回到 Graal 编译器。

Graal 编译器是使用 Java 写的 JIT 编译器,虽然难免会让人联想到性能会比不上 HotSpot 使用 C++ 写的 C2 编译器,但是在各种实验之后,得到的数据显示对于 Java 应用而言,Graal 编译器和 C2 编译器的能力几乎不相上下(在已经预热完毕的前提下)。


而对于 Scala 应用来说,Graal 编译器更是能达到 10% 以上的优化,这也是为什么 Twitter 大规模的使用 GraalVM 替换掉原本的 HotspotVM。



不过在启动时,GraalVM 会比 HotspotVM 还慢,原因是必须先将 Graal 编译成机器码,这个是无可避免的。只是当预热完毕时,Graal 和 C2 的性能会不相上下,并且根据 Graal 的版本不断更新,这个数据只可能会更好。


2. 多语言并行


GraalVM 最一开始被发明出来,就是为了让 Java 可以在一个运行期内,同时使用多种语言,从官网称呼 GraalVM 为 High-Performance Polyglot VM,也可以发现 Oracle 对 GraalVM 定位是一个多语言 JVM。


为了实现多语言并行,GraalVM 引入了一层 Truffle framework,只要实现了该语言的直译器,就可以在 Java 应用中使用该语言。


目前官方支持的语言仅有 Python、R、JavaScript,后续会陆续增加。



使用示例:


public class Main {
public static void main(String[] args) {
System.out.println("Hello World from Java!");

Context context = Context.newBuilder().allowAllAccess(true).build();

context.eval("js", "print('Hello World from JavaScript!');");
context.eval("python", "print('Hello World from Python!')");
context.eval("ruby", "puts 'Hello World from Ruby!'");
}
}

Hello World from Java!
Hello World from JavaScript!
Hello World from Python!
Hello World from Ruby!


3. 快速启动


GraalVM 还有最后一项技术,就是 Native Image 快速启动,这项技术是在编译期时,就将 Java 应用直接编译成二进制的机器码,让这个程序可以像一般二进制文件运行。



Native Image 带来的好处是可以更快速的启动一个 Java 应用,以往如果要启动 Java 程序,需要先启动 JVM 再载入 Java 代码,然后再把 .class 字节码即时编译成机器码交给机器执行,非常耗时间和耗内存;而如果使用 Native Image,可以取得一个更小更快速的镜像,适合用在云部署上。


Native Image 之所以可以快速启动,是因为他底层使用了 Ahead-of-time Compile(提前编译)。也就是说,在编译期会把所有相关的东西,包含一个底层 VM,一起编译成机器码。这个底层 VM 是 GraalVM 内部才有的东西,只包含最基本的线程机制、垃圾回收,尽可能的缩小必要的 JVM 体积。



虽然 Native Image 听起来很厉害,但是也有不可磨灭的缺点,就是使用 Native Image 程序时吞吐量会下降。原因是因为 Java 程序很大一部分的优化都在 JIT 编译器中,而 Native Image 是没有用到任何 JIT 提供的好处。


还有一个缺点,Native Image 并没有办法动态的加载类(因为所有东西必须要在编译期就决定好),所以也没办法使用反射等相关机制。


不过对于这个问题,GraalVM 也有提出相对应的解法,就是在编译时,把所有可能的类全部编译进来,所以反射机制还是可以支持的,不然的话,整个 Spring Framework 就不能使用 Native Image 了。


目前 Spring 5 也打算开始支持 GraalVM Native-Image 的开箱即用设定,可以想像无服务器计算的 Java 应用可能是之后的趋势,毕竟要有 Native Image 的快速启动特性,才能够达到无服务器计算的初衷。



补充一下:无服务器计算就是指 Fuction as a Service,目的是希望应用不用一直运行着,只有当有请求来的时候,才快速启动这个应用,然后请求一走就停掉这个应用。换句话说,不让应用作为后台程序持续的启动着,而是有需要的时候才开启。


推荐阅读  点击标题可跳转

JVM 的那些设置参数你都知道吗

OOP 多态机制在 JVM 中的实现

Spring Boot项目优化和JVM调优


看完本文有收获?请转发分享给更多人

关注「ImportNew」,提升Java技能

好文章,我在看❤️


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存