可以看到在第五次迭代之后,代码片段被 JIT 编译了:
--------------------------------5 iteration21456bDemo::
可以看到,与square
方法一起,构造方法也被 JIT 编译了 。在for
循环中调用square
之前要先构造Demo
实例,所以构造方法的解释次数同样达到 JIT 编译阈值 。这个例子说明了在解释发生之后何时 JIT 会介入 。
要查看编译后的代码,需要使用-XX:+PrintAssembly
标志,该标志仅在库路径中有反汇编器时才起作用 。对于 OpenJDK,使用hsdis
作为反汇编器 。下载合适版本的反汇编程序库,在本例中是hsdis-amd64.so
,并将其放在Java_HOME/lib/server
目录下 。使用时还需要在-XX:+PrintAssembly
之前增加-XX:+UnlockDiagnosticVMOptions
选项 。否则 , JVM 会给你一个警告 。
完整命令如下:
$ java -Xbatch -XX:+PrintCompilation -XX:CompileCommandFile=hotspot_compiler \\ -XX:-TieredCompilation -XX:CompileThreshold=5 -XX:+UnlockDiagnosticVMOptions \\ -XX:+PrintAssembly Demo[...]5 iteration17856bDemo::
我只截取了输出中与Demo.java
相关的部分 。
现在再来看看 AOT 编译 。它是在 JDK9 中引入的特性 。AOT 是用于生成.so
这样的库文件的静态编译器 。用 AOT 可以将指定的类编译成.so
库 。这个库可以直接执行,而不用解释或 JIT 编译 。如果 JVM 没有检测到 AOT 编译的代码,它会进行常规的解释和 JIT 编译 。
使用 AOT 编译的命令如下:
$ jaotc --output=libDemo.so Demo.class
用下面的命令来查看共享库的符号表:
$ nm libDemo.so
要使用生成的.so
库,使用-XX:+
和
UnlockExperimentalVMOptions-XX:AOTLibrary
:
$ java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libDemo.so Demo1 iterationSquare(i) = 1Time taken= 7831139--------------------------------2 iterationSquare(i) = 4Time taken= 36619[...]10 iterationSquare(i) = 100Time taken= 42085
JVM解释和编译指南 。小编来告诉你更多相关信息 。
JVM解释和编译指南从输出上看,跟完全用解释的情况没有区别 。为了确认 AOT 发挥了作用 , 使用-XX:+PrintAOT
:
$ java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libDemo.so -XX:+PrintAOT Demo281loaded./libDemo.soaot library801aot[ 1]Demo.main([Ljava/lang/String;)V802aot[ 1]Demo.square(I)I803aot[ 1]Demo.
要确认没有发生 JIT 编译 , 用如下命令:
$ java -XX:+UnlockExperimentalVMOptions -Xbatch -XX:+PrintCompilation \\ -XX:CompileCommandFile=hotspot_compiler -XX:-TieredCompilation \\ -XX:CompileThreshold=3 -XX:AOTLibrary=./libDemo.so -XX:+PrintAOT Demo191loaded./libDemo.soaot library771aot[ 1]Demo.square(I)I772aot[ 1]Demo.main([Ljava/lang/String;)V773aot[ 1]Demo.
需要特别注意的是,修改被 AOT 编译了的源代码后,一定要重新生成.so
库文件 。否则 , 过时的的 AOT 编译库文件不会起作用 。例如,修改square
方法 , 使其计算立方值:
//Demo.javapublic class Demo {public int square(int i) throws Exception {return(i*i*i);}public static void main(String[] args) throws Exception {for (int i = 1; i
重新编译Demo.java
:
$ java Demo.java
但不重新生成libDemo.so
。使用下面命令运行Demo
:
$ java -XX:+UnlockExperimentalVMOptions -Xbatch -XX:+PrintCompilation -XX:CompileCommandFile=hotspot_compiler -XX:-TieredCompilation -XX:CompileThreshold=3 -XX:AOTLibrary=./libDemo.so -XX:+PrintAOT Demo201loaded./libDemo.soaot library741njava.lang.invoke.MethodHandle::linkToStatic(LLLLLL)L (native)(static)2 iterationsqrt(i) = 8Time taken= 43838--------------------------------3 iteration13756bDemo::
可以看到,虽然旧版本的libDemo.so
被加载了,但 JVM 检测出它已经过时了 。每次生成.class
文件时,都会在类文件中添加一个指纹,并在 AOT 库中保存该指纹 。修改源代码后类指纹与旧的 AOT 库中的指纹不匹配了,所以没有执行 AOT 编译生成的原生机器码 。从输出可以看出,现在实际上是 JIT 在起作用(注意-XX:CompileThreshold
被设置为了 3) 。
AOT 和 JIT 之间的权衡如果你的目标是减少 JVM 的预热时间 , 请使用 AOT,这可以减少运行时负担 。问题是 AOT 没有足够的数据来决定哪段代码需要预编译为原生代码 。相比之下,JIT 在运行时起作用,却对预热时间有一定的影响 。然而,它将有足够的分析数据来更高效地编译和反编译代码 。
- SpringBoot与HttpClient:轻松实现GET和POST请求
- Linux系统中安装MATLAB和Mathematica
- 如何在Vim编辑器中剪切、复制和粘贴
- oppor11上市时间和价格 oppor11现在多少钱
- 超频对cpu损害大吗 超频cpu和不超频的区别
- 苹果12promax和12pro参数对比 苹果12promax和12pro那个好
- 华为p60玩机技巧和方法 p60手机配置参数
- 添加打印机的方法和步骤 win7电脑如何添加打印机设备
- 手机怎么阻止和拦截陌生人短信 苹果屏蔽短信怎么设置
- 如何区分独立显卡和集成显卡 买电脑独立显卡怎么看型号