Bootstrap

基于静态编译构建微服务

一、静态编译技术

提前编译(Ahead-of-Time Compilation,AOT Compilation)或者叫静态编译在 Java 领域很早就被提了出来。其核心思想就是将 Java 程序的编译阶段提前到程序启动前,然后在编译阶段进行代码编译优化,让程序启动既巅峰,消除冷启动,降低运行时内存开销。

Java 领域静态编译的实现技术有很多,其中最具代表性的还属 Oracle 推出的 GraalVM 开源高性能多语言运行时平台。

GraalVM 中通过提供 Truffle 解释器实现框架,让开发人员可以使用 Truffle 提供的 API 快速实现特定语言的解释器从而实现对上图中各种编程语言所写的程序都能进行编译运行的效果,从而成为一个多语言运行时平台。GraalVM 实现静态编译能力的编译器就是 GraalVM JIT Compiler。静态编译框架和运行时由 Substrate VM 子项目实现,兼容 OpenJDK 运行时实现,提供了原生镜像程序运行时的异常处理、同步调度、线程管理、内存管理等功能。

因此,GraalVM 不仅可以作为一个多语言运行时平台,而且由于其中提供的 GraalVM JIT Compiler 静态编译器,其可用来对 Java 程序进行静态编译。

基于 GraalVM 的静态编译与常规的 JVM 解释执行方式有哪些区别?

基于静态编译的 Java 程序相比于目前应用广泛的 JVM 运行时编译 Java 程序整个从代码编写到编译执行的区别如下图 所示:

 相比于 JVM 运行时方式,静态编译在运行之前会先对程序解析编译,然后生成一个跟运行时环境强相关的 native image 可执行文件,最后直接执行该文件即可启动程序进行执行。

 静态编译过程到底会对 Java 程序做哪些解析操作?静态编译后的可执行程序垃圾回收问题怎么解决?

 

左侧前三个输入内容 Applicaton,Libraries 和 JDK 是一个 Java 程序编译运行必备的三部分,不必多说。而 Substrate VM 就是 GraalVM 中实现静态编译的核心部分,在整个静态编译过程中扮演了重要作用。

其中在静态分析过程中,如上图中间部分中所绘制,Substrate VM 通过上下文不敏感的指向分析(Points-to Analysis)来对应用程序做静态分析,其可以在不需要运行程序的情况下,基于源程序分析给出所有可能的可达函数列表然后作为后续编译阶段的输入对程序进行静态编译。该过程由于静态分析的局限性,无法覆盖 Java 中的反射、动态代理、JNI 调用等动态特性。这也造成了很多的 Java 框架由于在实现过程中使用了大量的上述特性,因此,都难以直接基于 Substrate VM 完成对自身所有代码的静态分析,需要通过额外的外部配置来解决静态分析本身的不足。

 Spring 社区因此开发了 AOT Engine来帮助解决 Spring 项目对其中的反射,动态代理等内容进行静态分析处理并将其转换为 Substrate VM 能在编译阶段可识别的内容,确保对 Spring 应用可基于 Substrate VM 顺利完成静态编译。

 

在静态分析完成后,基于静态分析结果的可达函数列表,调用上文介绍的 GraalVM 中的 GraalVM JIT Compiler 编译器将应用程序编译为与目标平台强相关的本地代码以完成编译过程。

编译完成后,就会进入到上一个图右侧 Native 可执行文件生成阶段。在该过程中,Substrate VM 会将静态编译阶段确定和初始化的内容以及跟 Substrate VM 运行时以及 JDK 库中的数据一起保存到最终可执行文件的 Image Heap 中。其中 Substrate VM 运行时就为最终可执行文件提供了运行过程中所需的垃圾回收、异常处理等能力。对于垃圾回收这块,在一开始的 GraalVM 社区版中仅提供了 Serial GC。企业版中提供了能力更强的 G1 GC。不过在最新的社区版中 GraalVM 团队也引入了 G1 GC以便为广大开发者提供更强大的静态编译使用能力。

;