GraalVM 背景

新、旧编程语言的兴起躁动,说明必然有其需求动力所在,譬如互联网之于JavaScript、人工智能之于Python,微服务风潮之于Golang等等。大家都清楚不太可能有哪门语言能在每一个领域都尽占优势,Java已是距离这个目标最接近的选项,但若“天下第一”还要百尺竿头更进一步的话,似乎就只能忘掉Java语言本身,踏入无招胜有招的境界。

  • 更进一步提升JVM上运行的程序的性能
  • 通过预编译(ahead-of-time)编译Java程序为原生可执行程序
  • 多种编程语言混编在一个程序中(polyglot)
  • 类似于LLVM,GraalVM也提供了方便的机制方便开发新的编程语言

官方网站在: https://www.graalvm.org/

当前痛点

在云原生时代,Java程序是有很大的劣势的,为什么这么说呢?一般的Java应用程序都要几十兆的内存,启动也不不快。

最流行的SpringBoot/SpringCloud微服务框架为例,启动一个已经优化好,很多bean需要lazy load的application至少需要3-4秒时间,内存需要几百兆,业务逻辑稍微复杂一点点,没有1G以上的内存是很难满足业务的需要呢?

那么在云原生时代,一个充满黑科技的JVM介绍给大家,它能帮助我们让Java程序的启动速度加快100倍,内存只需要原来的五分之一,甚至更少。

Graalvm的介绍

  • GraalVM是2018年Oracle开发的下一代JVM实现,被官方称为“Universal VM”和“Polyglot VM”,这是一个在HotSpot虚拟机基础上增强而成的跨语言全栈虚拟机,可以作为“任何语言”的运行平台使用。

  • 这里“任何语言”包括了Java、Scala、Groovy、Kotlin等基于Java虚拟机之上的语言,还包括了C、C++、Rust等基于LLVM的语言,同时支持其他像JavaScript、Ruby、Python和R语言等等。

GraalVM可以无额外开销地混合使用这些编程语言,支持不同语言中混用对方的接口和对

象,也能够支持这些语言使用已经编写好的本地库文件。

它的口号“Run Programs Faster Anywhere”就能感觉到一颗蓬勃的野心

Graalvm性能的对比

GraalVM的性能真的不错。以JDK 8为例

  • OpenJDK
  • Oracle JDK

其中OpenJDK是通过“GPL v2 with CE”协议开源的,可以免费商用的。

之前在用Apache Spark测试性能时, 对比一下两者性能, 稍微数据量大点的查询,会发现Oracle JDK一般都会比OpenJDK快30%以上。

  • 而GraalVM分为社区版和商业版,其中GraalVM的社区版也是采用了和OpenJDK一样的“GPL v2 with CE”协议开源的。

  • 对于GraalVM的社区版,非常惊喜的发现其比Oracle JDK也会快10%以上。

  • 没有试过GraalVM的商业版, 官方报道,其商业版比社区版提升的性能更多

Graalvm主要特性

  • 高性能的现代Java
  • 占用资源少,启动速度快
  • JavaScript,Java, Ruby以及R混合编程
  • 在JVM上运行原生语言
  • 跨语言工具
  • JVM应用扩展
  • 原生应用扩展
  • 本地Java库
  • 数据库支持多语言
  • 创建自己的语言

Graalvm工作原理

GraalVM的基本工作原理是将这些语言的源代码(例如,JavaScript)或源代码编译后的中间格式(例如,LLVM字节码、Class字节码)通过解释器转换为能被GraalVM接受的中间表示(Intermediate Representation,IR),譬如设计一个解释器专门对LLVM输出的字节码进行转换来支持C和C++语言,这个过程称为“程序特化”(Specialized,也常称为Partial Evaluation)。

GraalVM提供了Truffle工具集来快速构建面向一种新语言的解释器,并用它构建了一个称为Sulong的高性能LLVM字节码解释器。

从某个角度来看,GraalVM才是真正意义上与物理计算机相对应的高级语言虚拟机,因为它与物理硬件的指令集一样,做到了只与机器特性相关而不与某种高级语言特性相关。

Graalvm的高等优化能力

Oracle Labs的研究总监Thomas Wuerthinger在接受采访时谈到:“随着GraalVM1.0的发布,已经证明了拥有高性能的多语言虚拟机是可能的,并且实现这个目标的最佳方式不是通过类似Java虚拟机和微软CLR那样带有语言特性的字节码”。

本来就不以速度见长的语言运行环境,由于GraalVM本身能够对输入的中间表示进行自动优化,在运行时还能进行即时编译优化,往往使用GraalVM实现能够获得比原生编译器更优秀的执行效率,譬如Graal.js要优于Node.js、Graal.Python要优于CPtyhon,TruffleRuby要优于Ruby MRI,FastR要优于R语言等等。

Graalvm与Hotspot的对比

GraalVM本来就是在HotSpot基础上诞生的,天生就可作为一套完整的符合Java SE8标准Java虚拟机来使用。

它和标准的HotSpot差异主要在即时编译器上,其执行效率、编译质量目前与标准版的HotSpot相比也是互有胜负。

Oracle Labs和美国大学里面的研究院所做的最新即时编译技术的研究全部都迁移至基于GraalVM之上进行了,其发展潜力令人期待。

如果Java语言或者HotSpot虚拟机真的有被取代的一天,那从现在看来GraalVM是希望最大的一个候选项,这场革命很可能会在Java使用者没有明显感觉的情况下悄然而来,Java世界所有的软件生态都没有发生丝毫变化,但天下第一的位置已经悄然更迭。

Graalvm即时编译器

自JDK 10起,HotSpot中又加入了一个全新的即时编译器:Graal编译器,看名字就可以联想到它是来自于Graal VM。

C1/C2即时编译器

对需要长时间运行的应用来说,由于经过充分预热,热点代码会被HotSpot的探测机制准确定位捕获,并将其编译为物理硬件可直接执行的机器码,在这类应用中Java的运行效率很大程度上是取决于即时编译器所输出的代码质量。

HotSpot虚拟机中包含有两个即时编译器:

  • 编译时间较短但输出代码优化程度较低的客户端编译器(简称为C1)
  • 编译耗时长但输出代码优化质量也更高的服务端编译器(简称为C2)

通常它们会在分层编译机制下与解释器互相配合来共同构成HotSpot虚拟机的执行子系统的。

C2即时编译器

Graal编译器是作为C2编译器替代者的角色登场的。C2的历史已经非常长了,可以追溯到Cliff Click大神读博士期间的作品,这个由C++写成的编译器尽管目前依然效果拔群,但已经复杂到连Cliff Click本人都不愿意继续维护的程度。

Graal编译器

而Graal编译器本身就是由Java语言写成,实现时又刻意与C2采用了同一种名为“Sea-of-Nodes”的高级中间表示(High IR)形式,使其能够更容易借鉴C2的优点。

Graal编译器比C2编译器晚了足足二十年面世,有着极其充沛的后发优势,在保持能输出相近质量的编译代码的同时,开发效率和扩展性上都要显著优于C2编译器,这决定了C2编译器中优秀的代码优化技术可以轻易地移植到Graal编译器上,但是反过来Graal编译器中行之有效的优化在C2编译器里实现起来则异常艰难。

这种情况下,Graal的编译效果短短几年间迅速追平了C2,甚至某些测试项中开始逐渐反超C2编译器。

Graal能够做比C2更加复杂的优化:

  • “部分逃逸分析”(Partial Escape Analysis)
  • 比C2更容易使用“激进预测性优化”(Aggressive Speculative Optimization)的策略
  • 支持自定义的预测性假设
未来可期

Graal编译器尚且年幼,还未经过足够多的实践验证,所以仍然带着“实验状态”的标签,需要用开关参数去激活,这让笔者不禁联想起JDK 1.3时代,HotSpot虚拟机刚刚横空出世时的场景,同样也是需要用开关激活,也是作为Classic虚拟机的替代品的一段历史。

Graal编译器未来的前途可期,作为Java虚拟机执行代码的最新引擎,它的持续改进,会同时为HotSpot与Graal VM注入更快更强的驱动力。

编译为原生执行程序

编译为原生程序有一定的假设条件,比如:

  • 尽量少的JNI调用
  • 尽量少的使用反射
  • 尽量少的class loader隔离等

当没有用这些复杂功能的时候,很容易可以使用GraalVM提供的 native image 编译Jar为可执行程序。

当然即使当程序使用了 JNI、反射时,也没关系,我们可以使用一些配置文件告诉GraalVM单独处理这些信息,比如:

  • 通过参数 -H:JNIConfigurationFiles 告诉JNI相关配置JSON文件
  • 通过参数 -H:ReflectionConfigurationFiles 告诉反射相关配置JSON文件

稍微会复杂一些,但是只要有足够的耐心,理论上也是可以编译成功的!

不过我们可以使用一些原生支持GraalVM native image的框架, 比如:Quarkus。

GraalVM的原生编译非常适合微服务和 Serverless

当可以把Java程序也编译为原生的可执行程序后 (目前GraalVM已经支持编译为Windows, MacOS, Linux上的原生程序),最主要的两个变化:

  • 启动时间变短了,之前启动一个有“依赖注入”的Java程序,可能启动时间要2秒以上。如果Java程序是要长期运行的,那启动时间稍慢一点是没问题的,但是对于 Serverless 应用,这就变为冷启动(cold start)了,影响比较大。

  • 程序运行的内存需求变小了,之前启动一个Java程序,控制的好的话(heap设置的比较小),也要100M以上的内存,但是编译为原生程序后,只需要4M内存就可以了。 这样同样的一台机器就可以启动非常多的进程,适合简单的微服务。

参考资料

🏆【JVM深层系列】「云原生时代的Java虚拟机」针对于GraalVM的技术知识脉络的重塑和探究的更多相关文章

  1. 云原生时代,Java的危与机(周志明)

    说明 本篇文章是转载自周志明老师的文章,链接地址:https://www.infoq.cn/article/RQfWw2R2ZpYQiOlc1WBE 今天,25 岁的 Java 仍然是最具有统治力的编 ...

  2. 云原生时代的Java

    原文链接(作者:周志明):https://time.geekbang.org/column/article/321185 公开课链接:https://time.geekbang.org/opencou ...

  3. JVM规范系列第3章:为Java虚拟机编译

    Oracle 的 JDK 包括两部分内容:一部分是将 Java 源代码编译成 Java 虚拟机的指令集的编译器,另一部分是用于Java 虚拟机的运行时环境. 第一部分应该说的是 Javac 这个前置编 ...

  4. 云原生时代高性能Java框架—Quarkus(一)

    --- Quarkus&GraalVM介绍.创建并启动第一个项目 Quarkus系列博文 Quarkus&GraalVM介绍.创建并启动第一个项目 构建Quarkus本地镜像.容器化部 ...

  5. 云原生时代高性能Java框架—Quarkus(二)

    --- *构建Quarkus本地镜像.容器化部署Quarkus项目* Quarkus系列博文 Quarkus&GraalVM介绍.创建并启动第一个项目 构建Quarkus本地镜像.容器化部署Q ...

  6. 进击的 Java ,云原生时代的蜕变

    作者| 易立 阿里云资深技术专家 导读:云原生时代的来临,与Java 开发者到底有什么联系?有人说,云原生压根不是为了 Java 存在的.然而,本文的作者却认为云原生时代,Java 依然可以胜任&qu ...

  7. 云原生时代 给予.NET的机会

    .NET诞生于与Java的竞争,微软当年被罚款20亿美元. Java绝不仅仅是一种语言,它是COM的替代者! 而COM恰恰是Windows的编程模型.而Java编程很多时候比C++编程要容易的多,更致 ...

  8. .NET 在云原生时代的蜕变,让我在云时代脱颖而出

    .NET 生态系统是一个不断变化的生态圈,我相信它正在朝着一个伟大的方向发展.有了开源和跨平台这两个关键优先事项,我们就可以放心了.云原生对应用运行时的不同需求,说明一个.NET Core 在云原生时 ...

  9. 【转】.NET 在云原生时代的蜕变,让我在云时代脱颖而出

    原创:张善友 原文:https://www.cnblogs.com/shanyou/p/12198741.html .NET 生态系统是一个不断变化的生态圈,我相信它正在朝着一个伟大的方向发展.有了开 ...

随机推荐

  1. Jmeter系类(32) - JSR223(2) | Groovy常见内置函数及调用

    常见内置函数及调用 获取相关函数 获取返回数据并转换为String字符串 prev.getResponseDataAsString() 例子 String Responsedata = prev.ge ...

  2. 传说中 VUE 的“语法糖”到底是啥?

    一.什么是语法糖? 语法糖也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语.指的是计算机语言中添加的一种语法,在不影响功能的情况下,添加某种简单的语 ...

  3. 低差异序列 (low-discrepancy sequences)之Halton序列均匀产生多维随机数的介绍与实现

    Halton序列 在统计学中,Halton序列是用于生成空间中的点的序列,如Monte Carlo模拟的数值方法,虽然这些序列是确定性的,但它们的差异性很低,也就是说,在许多方面看起来是随机的.它们在 ...

  4. Flawfinder在Python2和Python3环境下对代码进行扫描方法

    1. Flawfinder Flawfinder是一款开源的关于C/C++静态扫描分析工具,其根据内部字典数据库进行静态搜索,匹配简单的缺陷与漏洞. 官网:https://dwheeler.com/f ...

  5. NLP与深度学习(五)BERT预训练模型

    1. BERT简介 Transformer架构的出现,是NLP界的一个重要的里程碑.它激发了很多基于此架构的模型,其中一个非常重要的模型就是BERT. BERT的全称是Bidirectional En ...

  6. Hutool时间和日期相关工具

    日期时间工具 获取当前时间(1) public class HDateAndTime { public static void main(String[] args) { //获取当前时间 Date ...

  7. oracle扩展表空间

    1.  查看表空间的名字及文件所在的位置 select tablespace_name, file_id, file_name, round(bytes / (1024 * 1024), 0) tot ...

  8. SpringBoot-Thymeleaf模板引擎

    模板引擎,我们其实大家听到很多,其实jsp就是一个模板引擎,还有用的比较多的freemarker,包括SpringBoot给我们推荐的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他们的思想 ...

  9. python单例模式设计

    class MyTest(): my_obj = None def __new__(cls,*args,**kwargs): if not cls.my_obj: cls.my_obj =object ...

  10. 告别Vuex,发挥compositionAPI的优势,打造Vue3专用的轻量级状态

    Vuex 的遗憾 Vuex 是基于 Vue2 的 option API 设计的,因为 optionAPI 的一些先天问题,所以导致 Vuex 不得不用各种方式来补救,于是就出现了 getter.mut ...