[关闭]
@levinzhang 2022-07-09T00:22:21.000000Z 字数 4610 阅读 320

Leyden延迟了OpenJDK AOT编译器,转而优化JIT编译器

by

摘要:

Leyden项目的目标是解决“Java启动时间慢、达到性能峰值慢以及占用空间大的问题”。它想通过在OpenJDK中再次引入预先编译(Ahead-of-Tim,AOT)来实现这一点。但是,目前它转向了首先优化即时编译(Just-in-Time,JIT)的策略。Oracle的Graal项目已经实现了Leyden项目的目标,但其代价是Leyden目前竭力想避免的。


Leyden项目的目标是“解决Java启动时间慢、达到性能峰值慢和占用空间大等长期痛点问题”。它想通过在OpenJDK中“引入静态镜像的概念”来实现这一目标。静态镜像来自于对原生可执行文件的提前(Ahead-of-Time,AOT)编译。在两年没有公开的活动之后,Leyden项目在2022年5月改变了方向,首先优化即时(Just-in-Time,JIT)编译。由此产生的优化几乎肯定要比最初计划的要弱,它最早会在2025年底交付给主流Java开发者。Oracle的Graal项目已经实现了Leyden项目的目标,但其代价是该项目目前竭力想避免的。

Graal项目起源于Oracle Labs,并不是OpenJDK的一部分。它的GraalVM Native Image是一个Java AOT编译器,如今能够生成原生可执行文件。与Java的JIT编译器相比,它们有四个优势,即启动更快、内存和CPU占用更低、安全漏洞更少以及文件更小。

但是,这些成就是有代价的,那就是GraalVM Native Image对Java应用有一个所谓的封闭性假设(closed-world assumption)的要求,这对所有的Java的应用来说都是很难接受的。为什么呢?因为Java是一个动态语言,它在运行时赋予了应用很多的权力,比如反射、类加载,甚至构建类。有些特性在GraalVM Native Image的封闭世界里是无法正常运行的。这也就是Leyden项目现在想要“探索比封闭性假设更弱的约束,并发现它们能够实现哪些优化”的原因。尽管如此,Leyden项目“依然有希望[...]生成完全静态的镜像”,只不过“这是长期来看”的目标了。

OpenJDK以前曾经尝试过AOT编译

Leyden项目是OpenJDK对AOT编译的第二次尝试。第一次尝试是JEP 295 Ahead-of-Time Compilation的jaotc,并于2017年9月在JDK 9中交付。与GraalVM Native Image类似,它使用了Graal项目。但是,与GraalVM Native Image不同的是,它非常不受欢迎:当Oracle在Java 16构建版中移除jaotc时,“没有受到任何人的抱怨”。于是,Oracle在JDK 17中,基于JEP 410 Remove the Experimental AOT and JIT Compiler,干脆利落地移除了它。

对于OpenJDK项目来说,Leyden有着不同寻常的历史。Java语言的架构师Mark Reinhold在2020年4月提出了它,随后,OpenJDK在2020年6月将其批准为一个项目。但是,从批准到2022年5月创建邮件列表的两年时间里,没有看到该项目任何明显的进展。这也就是该项目为何刚刚起步,现在主要关注的是“概念,而不是代码”的原因。Reinhold指出,像“HotSpot JVM、C2编译器、应用类数据共享(application class-data sharing,CDS)以及jlink链接工具”都是优化的目标。值得注意的是,列表里缺失的一个组件是CRaC,它是一个OpenJDK项目,能够通过在磁盘中加载Java应用来减少启动时间。

通过反推可以得出可能的交付日期。现在,LTS版本的重要性已经超出了预期。Ben Evans,之前就职于性能监控公司New Relic,在Devoxx UK 2022上宣布“没有任何一个非LTS版本的市场份额超过了1%”。这表明,主流的Java开发人员只会从一个Java LTS版本迁移至另一个LTS版本。

因为Leyden项目现在刚刚开始,估计很少有成果能够以生产可用的状态进入2023年9月份发布的JDK 21(也就是下一个LTS版本)。所以,主流Java开发人员可能只有在2025年9月的LTS版本(JDK 25)中才能看到Leyden项目的第一批成果。基于这样的假设,Leyden项目最早会在2027年9月通过JDK 29向原生可执行文件提供AOT编译功能。InfoQ将继续关注Leyden项目的进展。

Spring Boot对Leyden项目的反应

在Leyden考虑的特性中,至少有一些需要应用框架的支持才能发挥最佳效果,比如jlink或CRaC。所以,InfoQ联系了Spring Boot、Quarkus和Micronaut的开发者,了解他们对Leyden公告的初步反应。

Spring Framework的项目负责人Juergen Hoeller对Leyden项目表示了认可:

Leyden项目是一个很有前途的倡议,与我们在Spring Framework 6和Spring Boot 3的大方向上是一致的。

Hoeller还欣然接受在Spring中支持CRaC:

CRaC堆快照可以作为改善Spring应用的启动时间的通用方案。在应用启动的最后阶段生成快照,此时几乎没有任何处于打开状态的文件或网络资源,这符合CRaC的预期。Spring甚至已经在应用上下文刷新结束时重置了它的通用缓存,在用请求相关的元数据动态地重新填充缓存之前清除了启动相关的元数据。在[......]应用上下文对快照事件的具体反应,以及改进通用组件的“快照安全”方面,我们肯定会在技术上可行的情况下,在Spring Framework 6.x产品线中努力为早期采用者赋予更多的能力。

Hoeller认为Spring将会很快支持jlink和Java平台模块系统(Java Platform Module System ,JPMS):

目前的Spring Framework 6.0的里程碑版本还不包括module-info描述符。但这在9月份M6里程碑版本的路线图上,在我们进入6.0的发布候选阶段时,会重新评估第三方生态系统的模块系统就绪情况。由于Leyden项目有可能将jlink变成一个更强大、更通用的工具,所以我们计划不仅为jlink目前的能力做好准备,也会考虑它进一步的演进。

Quarkus对Leyden项目的反应

Quarkus的联合创始人和共同负责人Jason Greene对Leyden项目发表了评论:

我们对Leyden项目修改Java语言规范以更好地支持静态镜像、原生编译和其他技术(如JVM检查点)的目标感到最为兴奋。此外,我们很高兴看到封闭性假设仍然可能是该项目的长期目标。

Greene也欣然接受在Quarkus中支持CRaC:

最近,对CRaC研究项目的初步支持已经由CRaC的负责人贡献给了Quarkus项目。不管运行时的目标类型是什么,Quarkus都会进行构建时的优化,所以在OpenJDK上运行时,我们依然能够看到相当可观的成本节省,而不仅限于GraalVM。在OpenJDK之上添加检查点的方式,比如CRaC,能够进一步优化启动时间。它无法带来类似于原生镜像那样的成本节省,但是对倾向于或必须采用JVM执行的应用来讲,未来这都是一个很有意思的可选方案。

但是,Greene对于在Quarkus中使用jlink和JPMS并没有表现出太高的热情:

截止到目前为止,jlink只是为基于JVM的应用的存储开销带来了好处(不管有没有它,内存开销和启动时间基本上都是一样的)。但是,在容器和Kubernetes应用中,常见的实践是在标准JVM基础镜像上建立新的层,这已经比将所有的应用切换到jlink上带来了更多的成本节省(因为每个人都会打包自己裁剪过的JVM)。在原生镜像的场景中,JVM的细粒度元素编译到了镜像中,所以在这种情况下,jlink也提供不了什么帮助。同样,对于JPMS,Quarkus已经通过Quarkus扩展实现了自己的模块化理念,允许我们将依赖集修剪到只包含所需的内容。Quarkus所采取的方式与简单扁平化classpath是兼容的,这也是大多数Java生态系统和构建工具如今所偏爱的方式。在成本方面,如果按照jlink的要求转向纯JPMS模块(没有自动模块),那么将意味着不仅对Quarkus,还对Quarkus构建所需的大量的库都会产生破坏性的变更。在考虑进行转换之前,我们希望看到这些因素能够更好地平衡。

Micronaut对Leyden项目的反应

Object Computing, Inc.(OCI)的首席软件工程师Sergio del Amo Caballero对Leyden项目没有发表Micronaut框架的官方声明。但他在最近一个关于在Micronaut上添加对CRaC支持的GitHub issue上对此进行了阐述。

Caballero还分享了2020年7月的一段YouTube视频,视频中Micronaut的创始人Graeme Rocher对JPMS进行了评论:Micronaut支持JPMS并发布了module-info文件,但必须要“在支持Java 8之间取得平衡”。JPMS是在Java 9中加入的,但Micronaut 3.5,即当前版本,仍然运行在Java 8上。

结论

到目前为止,OpenJDK还没有解决“Java启动时间慢、达到性能峰值慢以及占用空间大的问题”。首先,它的jaotc AOT编译器并没有得到足够的动力,并且已经废弃了。随后,Leyden项目开始对Java的原生编译进行标准化,但停滞了两年之久。

现在,Leyen项目已经转向首先优化JIT编译,情况正在好转:Spring和Quarkus都拥抱CRaC以减少启动时间。但是当涉及到实现较小的Java应用时,只有Micronaut坚持Leyden项目的建议,即使用JPMS。Spring计划在2022年底的6.0版本中支持JPMS,不过Spring生态系统可能还不会这样做。而Quarkus目前没有计划加入JPMS。

Leyden项目的成果,最早可以在2025年底以JEP的形式到达主流Java开发者手中。因此,至少在那之前,将GraalVM Native Image AOT编译器与Quarkus、Micronaut或即将推出的Spring Boot 3等框架结合起来,仍然是避免“Java启动时间慢、达到性能峰值慢以及占用空间大的问题”的最佳选择。

关于作者

Karsten Silz

作为一名全栈 Java 开发人员,Karsten Silz 在欧洲和美国工作了23年。2004年,他在美国合伙创立了一家提供软件产品的初创公司。Karsten领导了13年的产品开发,并在公司成功出售后离开。自2017年以来,他一直在德国和英国做承包商(Spring Boot、Angular、Flutter)。2020年,他作为CTO共同创立了SaaS初创公司“Your Home in Good Hands”。

查看英文原文:Project Leyden Delays OpenJDK AOT Compiler, Optimizes JIT Compiler Instead

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注