在熟悉了aot的一些基本操作以及一些使用模式后,我们看看常规的操作是怎么样的。
对核心类库编译
java核心类库可以说是调用比较频繁的代码,所以把核心类库进行编译,可以有效的提升启动速度。
jaotc --output libjava.base.so --module java.base
一般情况下,jdk是保证了核心类库的编译是没有问题的。上面的指令除非用的预览版本,那都是正常的。
合理设置参数
jaotc可以使用-J指定运行时参数,官方的例子中使用了gc参数和压缩指针参数。
jaotc -J-XX:-UseCompressedOops --output libtest.so AotTest.class
如果运行时没有-XX:-UseCompressedOops日志中会打印出一个异常。
Shared file ./libtest.so error: UseCompressedOops has different value 'false' from current 'true'
832 1 skipped ./libtest.so aot library
gc的也同理。
哪些运行时参数是必须编译时就设置的,这个我自己测试了-Xmx这些,是可以运行的。现在发现的其实就是那两个参数,这个只能说实践中慢慢确认了。
这里也就是出现了一个问题,我们的程序不一定都要用G1,有的也需要使用ps,堆小的是需要开启压指针的,堆大的确实不需要。针对这种情况,我们能做的就是把情况和组合枚举一下,然后编译出多个版本,启动的时候指定不同的版本,官方就推荐这么做的,甚至他还举了例子。
-XX:-UseCompressedOops -XX:+UseG1GC : libjava.base.so
-XX:+UseCompressedOops -XX:+UseG1GC : libjava.base-coop.so
-XX:-UseCompressedOops -XX:+UseParallelGC : libjava.base-nong1.so
-XX:+UseCompressedOops -XX:+UseParallelGC : libjava.base-coop-nong1.so
应该庆幸参数可能就这么少,如果运行时特别多的话,编译起来估计要疯的,得写脚本做循环遍历。然后用的时候得按照规则加载出合适的库,大部分时间都花在了脚本匹配上了,而且还得打开-XX:+PrintAOT,这个错误并不会让程序失败停止。还需要做日志分析。所以说这个用起来确认正确性还真是一个麻烦的事情。
aot与反射
我写了一个比较简单的demo,发现aot是支持反射的。
import java.lang.reflect.Field;
public class AotTest {
public static void main(String[] args) throws Exception {
Class<?> testB=Class.forName("TestB");
Field fields = testB.getDeclaredField("SS");
fields.setAccessible(true);
String ss = (String) fields.get(null);
System.out.println(ss);
}
}
public class TestB{
private final static String SS="ggg";
public static void main(String[] args) {
System.out.println("this is TestB");
}
}
我们把两个class文件打到一个库里。
jaotc --output libtest.so AotTest.class TestB.class
执行我们看到,TestB也是可以正常执行的。
java -XX:+PrintAOT -XX:AOTLibrary=./libtest.so AotTest
747 1 loaded ./libtest.so aot library
828 1 aot[ 1] AotTest.<init>()V
828 2 aot[ 1] AotTest.main([Ljava/lang/String;)V
828 3 aot[ 1] TestB.<init>()V
828 4 aot[ 1] TestB.main([Ljava/lang/String;)V
ggg
aot与lambda
import java.lang.reflect.Field;
public class AotTest {
public static void main(String[] args) throws Exception {
Class<?> testB=Class.forName("TestB");
Field fields = testB.getDeclaredField("SS");
fields.setAccessible(true);
String ss = (String) fields.get(null);
System.out.println(ss);
MathOperation addition = (int a, int b) -> a + b;
addition.operation(1, 2);
}
}
interface MathOperation {
int operation(int a, int b);
}
沿用上面的例子,加了一个lambda。我们看看结果。
$ java -XX:+PrintAOT -XX:AOTLibrary=./libtest.so AotTest
673 1 loaded ./libtest.so aot library
752 1 aot[ 1] AotTest.lambda$main$0(II)I
752 2 aot[ 1] AotTest.<init>()V
752 3 aot[ 1] AotTest.main([Ljava/lang/String;)V
753 4 aot[ 1] TestB.<init>()V
753 5 aot[ 1] TestB.main([Ljava/lang/String;)V
ggg
我们发现lambda也是可以正常运行的。
总结
以上的案例都是基于jdk11做的,相比9刚出aot的时候,支持力度更好,基本的反射以及lambda都是可以正常运行。
共同学习,写下你的评论
评论加载中...
作者其他优质文章