JVM 解释和编译指南( 四 )

需要特别注意的是,修改被 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 <= 10; i++) {System.out.println("" + Integer.valueOf(i)+" iteration");long start = System.nanoTime();int r= new Demo().square(i);System.out.println("Square(i) = " + r);long end = System.nanoTime();System.out.println("Time taken= " + (end-start));System.out.println("--------------------------------");}}}重新编译 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::<init> (5 bytes)13857bDemo::square (6 bytes)sqrt(i) = 27Time taken= 534649--------------------------------4 iterationsqrt(i) = 64Time taken= 51916[...]10 iterationsqrt(i) = 1000Time taken= 47132可以看到,虽然旧版本的 libDemo.so 被加载了 , 但 JVM 检测出它已经过时了 。每次生成 .class 文件时,都会在类文件中添加一个指纹,并在 AOT 库中保存该指纹 。修改源代码后类指纹与旧的 AOT 库中的指纹不匹配了,所以没有执行 AOT 编译生成的原生机器码 。从输出可以看出,现在实际上是 JIT 在起作用(注意 -XX:CompileThreshold 被设置为了 3) 。
AOT 和 JIT 之间的权衡如果你的目标是减少 JVM 的预热时间,请使用 AOT,这可以减少运行时负担 。问题是 AOT 没有足够的数据来决定哪段代码需要预编译为原生代码 。相比之下,JIT 在运行时起作用 , 却对预热时间有一定的影响 。然而,它将有足够的分析数据来更高效地编译和反编译代码 。




推荐阅读