在开发Spring Boot
应用或者其他JAVA
程序的过程中,启动慢、内存占用大是比较头疼的问题,往往需要更多的资源去部署,成本大幅提高。为了优化上述问题,常常使用优化程序、使用更小消耗的JVM、使用容器等措施。
现在有一个叫做Native Image
(原生镜像)的技术,可以将JAVA
应用的字节码直接编译为本地机器码,打包成本地可执行文件,运行应用时无需Java
虚拟机进行动态编译,因此启动速度很快、内存消耗也很低。
通常程序有两种运行方式:
JIT
是Just-in-time
的缩写,一般称为即时编译或动态编译。Java
源代码在运行的过程中,类加载器将需要运行的字节码处理并分配到内存中,然后JVM
执行引擎需要调用解释器将字节码翻译为计算机能执行的机器码,最后执行机器指令。
需要解释执行势必会造成运行效率降低,为了提高执行速度,JAVA
引入了 JIT
编译器。当某个方法或代码块运行特别频繁的时候,JVM
会将其标注为热点代码, JIT
编译器会将热点代码编译成本地机器相关的机器码,优化后进行缓存,下次执行这些代码时,直接调用缓存中的机器码,无需重复解释,在一定程度上提高了执行速度。
JAVA
一直在努力提高启动和运行时性能,希望其能够在更广泛的场景达到或接近本地语言的性能。虽然引入了JIT
编译器,但是需要花费较长时间才能热身完,而且有些Java
方法还没法编译,性能方面也会下降。
AOT
是Ahead-of-Time
的缩写,一般称为静态编译。程序在执行前全部被翻译为机器码,可以直接运行二进制文件,比如C++
就是使用静态编译。
在 JDK 9
中, AOT
作为实验特性被引入,只支持 java.base
模块可以编译成AOT
库,使用jaotc
工具将Java
类文件编译为本机代码,避免了 JIT
预热等各方面的开销。但是实际运行效果不尽人意,最终在JDK 16
中被删除。
在JDK 17
中,也移除了实验性的AOT
与JIT
,彻底拥抱GraalVM
实现静态编译。
在当前微服务、云原生盛行的时代,JAVA 程序
显得越来越臃肿,虽然使用AOT
也有诸多缺点,比如打包时间长、舍弃平台无关性、反射、JNI、动态代理的分析能力有限。但是JAVA
必定会向AOT
发展,否则在云原生时代,可以能被其他后起之秀慢慢蚕食市场。
GraalVM
是一个高性能跨语言虚拟机,其目的是提升Java
和其他JVM
语言编写程序的执行速度,同时也为JavaScript
、Python
和许多其他流行语言提供运行时环境。起始于 2011 年 Oracle
实验室的一个研究项目。
GraalVM
三大核心:
Java
虚拟机提供高性能的JIT
编译器AOT
编译器,提前将 Java
字节码编译为本机机器码。GraalVM
的Truffle
语言实施框架可与 GraalVM
编译器协作,以卓越性能运行 JavaScript、Python、Ruby
以及 JVM
支持的其他语言。GraalVM
提供了两种运行Java
应用程序的方法:
HotSpot JVM
上使用实时JIT
编译器AOT
将Java
应用程序编译的本地可执行文件GraalVM
的优点:
帮助开发人员显著提升应用的性能效率,同时降低IT
成本。
构建现代 Java
应用,通过微服务和容器来满足云原生需求,微服务是执行单一功能的小型、独立微应用。在现实中,业务应用通常要使用数百项服务,每项服务都需要快速启动,以尽可能降低延迟和云使用成本。
可以构建一个各种编程语言基于单一 JVM
运行的生态系统,提高开发效率。
GraalVM
的缺点:
Java
的平台无关性,编译为本地执行文件,不同操作系统的服务器,编译出来的文件不一样,比如 Windows
编译出来的文件,并不能在Linux
系统运行,也就让JAVA
丢失了平台无关性。JAVA
设计之初,一次编译、到处运行是其最重要的特性,但是现在容器技术的出现,该特性显得很牵强。CGLIB
动态代理这些和字节码打交道的机制,是在程序运行时动态调用,无法经过 AOT
编译成原生代码,构建时还需要提供各种配置文件去适配。GraalVM
提供了多种操作模式。
1、JVM运行时模式
在HotSpot JVM
上运行程序时,默认使用GraalVM
编译器作为顶级JIT
编译器。在运行时,应用程序在JVM上
正常加载和执行。JVM
将字节码传递给编译器,编译器将其编译为机器代码并将其返回给JVM
。
2、原生镜像
Native Image
是一种创新技术,它将Java
代码编译为独立的本地可执行文件或本地共享库。在构建本机可执行文件期间,处理的Java
字节码包括所有应用程序类、依赖项、依赖于第三方的库以及所需的任何JDK类。生成的本地可执行文件特定于每个操作系统和机器体系结构,并不需要JVM
。
3、Java on Truffle
Java on Truffle
是一个 JVM
实现,它使用了 Truffle
多语言执行框架。提供了Java
虚拟机所有的核心组件,实现了与Java
运行时环境库相同的API
,并重用GraalVM中
的所有JAR
和本机库。支持多语言互操作,例如,JavaScript
程序可以运行Ruby
方法,无需制作副本就能共享数值。基于JVM
运行时,Truffle
能够与GraalVM
编译器协作,将受支持语言编译为本机机器码,从而优化性能。
了解了GraalVM
之后,我们着重了解并使用Native Image
技术将一个Spring Boot 3
项目编译为一个可执行二进制文件。
Native Image
:是一种将Java
代码提前编译为二进制文件的技术,即本机可执行文件。本机可执行文件只包含运行时所需的代码,即应用程序类、标准库类、语言运行时以及来自JDK的静态链接本机代码。
Native Image
处理应用程序类和其他元数据,以创建特定操作系统和体系结构的二进制文件。首先,本地镜像工具对代码执行静态分析,以确定应用程序运行时可访问的类和方法。其次,它将类、方法和资源编译成二进制文件。整个过程被称为构建,以明确区分它与Java
源代码到字节码的编译。
Native Image
生成的可执行文件优点:
Spring Native
是Spring
社区的一个开源框架,可以通过GraalVM
将Spring
应用程序编译成原生镜像。
官方推荐使用Spring Boot 3
+GraalVM
官方构建工具实现原生镜像构建,所以要注意Spring Native
已经没必要再去研究及使用了
WIN键 搜索环境变量,即可打开。
如果之前配置过java的环境变量 可以直接替换掉JAVA_HOME
如果没有配置过,需要配置JAVA_HOME,并在系统path中添加 %JAVA_HOME%\bin
点击“确定”按钮保存更改。
如果输出的结果包含GraalVM的版本信息,则说明安装成功。
已经成功安装和配置了GraalVM在Windows上,可以开始使用它进行Java开发或者运行其他语言的程序。接下来需要安装native-image。
Native Image
:是一种将Java
代码提前编译为二进制文件的技术,即本机可执行文件。
gu.cmd install native-image
可以使用命令查看,已经安装的功能
gu.cmd list
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello native image, World!");
}
}
javac HelloWorld.java
native-image HelloWorld
报错:要安装 Visual Studio 2022
链接:
最后一个命令生成在当前工作目录中命名的可执行文件。 调用它将执行类的本机编译代码,如下所示:Hello native image, World!
成功!