What is Project Leyden?
Address long-term pain points of Java’s start-up time, time to peak performance and large footprint.
Leyden项目计划最早于2020年5月份左右提出,距该文章已经被讨论了2年多。作为Java未来的改进方向,与其并行的还有其他5类JDK Project,包括:Valhalla、Amber、Loom、Panama、Portola。此前我们已经通过虚拟线程(Virtual Thread)了解了Loom相关的内容。在这5大Project中最为复杂且意义最为深远的当属Leyden计划。
Leyden本意“莱顿瓶”,也是“Capturing lightning in a Bottle(捕获瓶子中的闪电)”的意思。Leyden计划的目标非常明确,那就是“Improve the startup time, warmup time, and footprint of Java programs.(缩短Java程序的启动时间、预热时间和占用空间)”。Java诞生28年以来这些问题成为了这门语言长期饱受争议的诟病。
随着云原生与分布式服务对于Java性能的不断追求,Project Leyden将重点着手于解决这些问题。Project Loom已经让我们窥探到了JDK 21的虚拟线程(可能少部分人乐意称其为Java的协程,这里不做评价)的强大性,那么也行在未来,Project Leyden的实现可能将让Java开发者享受与Go语言相媲美的性能。
Means of Project Leyden
Project Leyden的实现手段和方法有如下几点:
Shift computation temporally, later and earlier in time.
Constrain Java’s natural dynamism, to enable more and better shifting.
Selectively, per the needs of each particular program.
Compatibly, to preserve program meaning.
它们主要强调了通过改变计算的时间(即在时间上早些或晚些进行计算)来实现其目标。为了实现更多和更好的计算转移,Leyden选择了限制一些Java的动态性。这种“转移”是根据每个特定程序的需要进行选择的,并且要确保与现有程序的兼容性,以保留程序的原始意义。
我们将重点关注“限制一些Java的动态性”这一点上,我们都知道Java是一种动态语言,具有很多动态特性,如动态类加载和反射。这些特性使得Java非常灵活,但也同样也存在一些性能问题。更具体的动态性主要体现在以下几个方面:
动态性 | 英译 | 常见场景 |
---|---|---|
反射 | Reflection | Cglib |
动态代理 | Dynamic Proxies | Cglib, AspectJ |
类加载器 | Class Loader | Bootstrap ClassLoader |
字节码操作 | Bytecode Manipulation | Java ASM |
JIT即时编译 | Just-In-Time Compilation | C1, C2 |
动态语言支持 | Dynamic Language Support | Graal VM |
限制一些Java的动态性也就意味着我们可能会失去Java反射,这是一个“链式反应”,接踵而来的是我们在Leyden项目中可能会失去动态代理、失去Spring框架。这也是Leyden所体现的“世界封闭性”,这意味着它将禁止动态加载类并严格地限制反射。这样做可以让JVM知道所有可能的代码和数据,从而简化代码分析的过程。
Why leyden choose to sacrifice dynamism?
Project Leyden的目标和Graal VM的目标非常相似,都是希望通过将Java程序编译为二进制程序来避免传统JVM启动和加载类的过程。得益于这样的优势,这两种技术都可以显著减少应用程序的启动时间和内存开销。为了实现这种编译,两者都不得不采用所谓的"封闭世界"假设,这意味着在编译时必须知道所有的代码和数据。
Java最初是为了“一次编写,到处运行”的目标而设计的。这意味着Java程序可以在任何支持Java虚拟机(JVM)的平台上运行,而不需要修改。为了实现这一目标,Java采用了字节码和JVM的设计,这使得Java具有很强的动态性和平台独立性。然而,这种动态性和平台独立性也带来了一些开销,特别是在启动时间和内存占用方面。在云和微服务环境中,这些开销可能会成为一个问题,因为这些环境通常需要快速启动和低内存占用。