起因是看到了大佬嘴中提到了一个关键词,查录一下
jaotc是什么?
-
官方解释:
jaotc
为已编译的 Java 方法生成本机代码的 Java 静态编译器. -
通俗解释:
jaotc
是在 Java9 中引入,用于支持对 Class 文件和模块进行提前编译的工具(AOT
),以减少程序的启动时间和到 达全速性能的预热时间. -
但由于这项功能必须针对特定物理机器和目标虚拟机的运行参数来使用,加 之限制太多,一般的Java 开发人员对此了解、使用普遍比较少。本节我们将用 Jaotc 来编译 Java SE 的基础库
-
验证环境:java11,windows10 64 位
example
- 快速浏览一下示例类:
public class HelloWorld {
public static void main(String[] argv) {
System.out.println(message());
}
public static String message() {
return "hello world";
}
}
- 在使用 AOT 编译器之前,我们需要使用 Java 编译器编译该类,得到 class 文件
> javac HelloWorld.java
- 然后,我们将生成的
HelloWorld.class
传递给 AOT 编译器,该编译器与标准 Java 编译器位于同一目录中:
> jaotc --output libHelloWorld.so HelloWorld.class
- 通过以上命令,在当前目录中生成了名为
libHelloWorld.so
的文件。
有了这个libHelloWorld.so
静态链接库,我们就可以使用这个静态链接库而不是Class
文件来输出 HelloWorld 了:
# 使用 so
> java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libHelloWorld.so
hello world
# 使用 class
> java HelloWorld
hello world
参数解释: -XX:AOT 库接受库的相对路径或完整路径。或者,我们可以将 so 库复制到 Java 主目录中的 lib 文件夹中,并且只传递库的名称。
- 为了验证 AOT 编译器编译后的代码被加载以及执行了.可以通过添加
-XX:+PrintAOT
作为JVM 参数
来加载的
java -XX:+UnlockExperimentalVMOptions -XX:+PrintAOT -XX:AOTLibrary=./libHelloWorld.so HelloWorld
# 输出结果
E:\>java -XX:+UnlockExperimentalVMOptions -XX:+PrintAOT -XX:AOTLibrary=./libHelloWorld.so HelloWorld
11 1 loaded ./libHelloWorld.so aot library
79 1 aot[ 1] HelloWorld.<init>()V
79 2 aot[ 1] HelloWorld.message()Ljava/lang/String;
80 3 aot[ 1] HelloWorld.main([Ljava/lang/String;)V
hello world
但是,这只能告诉我们库已加载,而不是实际使用。通过传递参数 -verbose
,我们可以看到库中的方法确实被调用了
java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libHelloWorld.so -verbose -XX:+PrintAOT HelloWorld
AOT 编译的库包含一个类指纹,该指纹必须与.class 文件的指纹匹配。
改动一下 java 文件,用以区分返回不同的消息:
public static String message() {
return "The JAOT compiler says 'Good morning'";
}
如果此时,我们不使用 AOT 去编译修改后的 java 文件,再次运行:
> javac HelloWorld.java
> java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libHelloWorld.so -verbose -XX:+PrintAOT HelloWorld
会发现输出结果是这样:
11 1 loaded ./jaotCompilation.so aot library
The JAOT compiler says 'Good morning'
也就是说最终,我们通过仅执行了一次 AOT 编译,后续任何对代码的修改,只需要生成对应的 class 文件,而无需再在 class 的基础上编译为 native code.
什么是 JIT 和 AOT,各自有什么优点与缺点?
- JIT(Just-in-time,动态(即时)编译,边运行边编译):吞吐量高,有运行时性能加成,可以跑得更快,并可以做到动态生成代码等,但是相对启动速度较慢,并需要一定时间和调用频率才能触发 JIT 的分层机制
- AOT(运行前编译):内存占用低,启动速度快,可以无需 runtime 运行,直接将 runtime 静态链接至最终的程序中,但是无运行时性能加成,不能根据程序运行情况做进一步的优化
- AOT 程序的典型代表是用 C/C++ 开发的应用,它们必须在执行前编译成机器码;
- 而 JIT 的代表非常多,如 JavaScript、Python 等。事实上,所有脚本语言都支持 JIT 模式。但需要注意的是 JIT 和 AOT 指的是程序运行方式,和编程语言并非强关联的,有的语言既可以以 JIT 方式运行也可以以 AOT 方式运行,如 Java 和 Python。它们可以在第一次执行时编译成中间字节码,之后就可以直接执行字节码。
参考阅读
------ 如果文章对你有用,感谢右上角 >>>点赞 | 收藏 <<<