Spring(十):提前编译:AOT(Spring6 新特性)

AOT 这个概念是和 JIT 相对应的,Spring6 新加入了对 AOT 的支持,通过这种方式进行编译,启动速度快、内存占用低,更适合云原生的要求。

AOT 概述

JIT 和 AOT

JIT 和 AOT 这个名词是指两种不同的编译方式,这两种编译方式的主要区别在于是否在「运行时」进行编译。

JIT,Just-in-time,动态(即时)编译,边运行边编译

  • 在程序运行时,根据算法计算出热点代码,然后进行 JIT 实时编译。

  • 吞吐量高,有运行时性能加成,可以跑得更快,并可以做到动态生成代码等。

  • 但是相对启动速度较慢,并需要一定时间和调用频率才能触发 JIT 的分层机制。

  • 编译需要占用运行时资源,会导致进程卡顿。

AOT,Ahead-of-time,指运行前编译,预先编译

  • AOT 编译能直接将源代码转化为机器码。
  • 内存占用低启动速度快,可以无需 runtime 运行,直接将 runtime 静态链接至最终的程序中。
  • 但是 AOT 无运行时性能加成,不能根据程序运行情况做进一步的优化。
  • 在程序运行前编译会使程序安装的时间增加。

简单来讲:JIT 即时编译指的是在程序的运行过程中,将字节码转换为可在硬件上直接运行的机器码,并部署至托管环境中的过程。而 AOT 编译指的则是,在程序运行之前,便将字节码转换为机器码的过程。

.java -> .class -> (使用jaotc编译工具) -> .so(程序函数库,即编译好的可以供其他程序使用的代码和数据)

使用 AOT 可以大幅提高启动编译和启动进程的速度,降低内存占用,更贴合云原生时代的需求。

Graalvm

Spring6 支持的 AOT 技术,这个 GraalVM 就是底层的编译器支持,Spring 也对 GraalVM 本机映像提供了一流的支持。GraalVM 是一种高性能 JDK,旨在加速用 Java 和其他 JVM 语言编写的应用程序的执行,同时还为 JavaScript、Python 和许多其他流行语言提供运行时加速。

GraalVM 提供两种运行 Java 应用程序的方法:

  • 在 HotSpot JVM 上使用 Graal 即时 (JIT) 编译器
  • 作为提前 (AOT) 编译的本机可执行文件。

GraalVM 的多语言能力使得在单个应用程序中混合多种编程语言成为可能,同时消除了外语调用成本。GraalVM 向 HotSpot Java 虚拟机添加了一个用 Java 编写的高级即时 (JIT) 优化编译器。

GraalVM 具有以下特性:

(1)一种高级优化编译器,它生成更快、更精简的代码,需要更少的计算资源

(2)AOT 本机图像编译提前将 Java 应用程序编译为本机二进制文件,立即启动,无需预热即可实现最高性能

(3)Polyglot 编程在单个应用程序中利用流行语言的最佳功能和库,无需额外开销

(4)高级工具在 Java 和多种语言中调试、监视、分析和优化资源消耗

总的来说对云原生的要求不算高短期内可以继续使用 2.7.X 的版本和 JDK8,不过 Spring 官方已经对 Spring6 进行了正式版发布。

Native Image

目前业界除了这种在 JVM 中进行 AOT 的方案,还有另外一种实现 Java AOT 的思路,那就是直接摒弃 JVM,和 C/C++ 一样通过编译器直接将代码编译成机器代码,然后运行。这无疑是一种直接颠覆 Java 语言设计的思路,那就是 GraalVM Native Image。它通过 C 语言实现了一个超微缩的运行时组件 —— Substrate VM,基本实现了 JVM 的各种特性,但足够轻量、可以被轻松内嵌,这就让 Java 语言和工程摆脱 JVM 的限制,能够真正意义上实现和 C/C++ 一样的 AOT 编译。这一方案在经过长时间的优化和积累后,已经拥有非常不错的效果,基本上成为 Oracle 官方首推的 Java AOT 解决方案。

Native Image 是一项创新技术,可将 Java 代码编译成独立的本机可执行文件或本机共享库。在构建本机可执行文件期间处理的 Java 字节码包括所有应用程序类、依赖项、第三方依赖库和任何所需的 JDK 类。生成的自包含本机可执行文件特定于不需要 JVM 的每个单独的操作系统和机器体系结构。

Native Image 构建过程

  1. 官网下载

  2. 解压文件,设置环境变量 GRAALVM_HOME ,并且配置 JAVA_HOME(位置和 GRAALVM_HOME 一样),配置 Path

  3. 使用命令 gu install native-image 安装 native-image

  4. 编写 Hello.java

    class Hello {
        public static void main(String[] args) {
            System.out.println("hello world!");
        }
    }
    
  5. 使用 javac 编译 Hello.java

  6. 编译后使用 native-image Hello 进一步编译为机器码(需要配置 C++ 编译环境)

  7. 执行编译出的 Hello.exe

小结

  • AOT 是与 JIT 相对的概念,两者的本质区别在于编译优化的时间,是在运行时还是在运行前。
  • Graalvm 是 Spring6 支持的 AOT 技术的底层编译器支持,Native Image 是 Graalvm 中的一种完全摈弃 JVM,直接编译为机器码的实现 AOT 的技术。