继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

aot实战

xpbob
关注TA
已关注
手记 152
粉丝 1.6万
获赞 380

动态字节码支持

我们知道aot是可以支持lambda的。而且从aot的日志上我们可以看出他把我们写的代码已经做了加载。lambda也是动态生成字节码的典型了,是不是动态生成的,aot也会全量支持呢。我们下面来验证这个问题。
lambda是核心类库,所以这次我们把核心类库也编译了。以防误差。

jaotc --output libjava.base.so --module java.base

编写一个lambda的简单demo。

public class AotTest {
    public static void main(String[] args) throws Exception {
              MathOperation addition = (int a, int b) -> a + b;
              addition.operation(1, 2);
    }
}

interface MathOperation {
    int operation(int a, int b);
}

我们可以通过增加参数,把动态生成的字节码打印成文件。利用-Djdk.internal.lambda.dumpProxyClasses。
利用类加载来打印类加载信息。-verbose:class。
打印aot的信息。-XX:+PrintAOT
把程序输出重定向到一个文件里去。

java  -verbose:class  -XX:+PrintAOT -Djdk.internal.lambda.dumpProxyClasses=.  -XX:AOTLibrary=./libtest.so,./libjava.base.so AotTest > 1.txt

我把动态生成的字节码就放在当前路径了,我们可以看到文件夹下多了一个AotTest$$Lambda$1.class。
我们在日志中可以搜到类加载信息。

[0.339s][info][class,load] AotTest$$Lambda$1/0x0000000800067840 source: AotTest

但是搜不到aot的信息。
说明aot本身对于动态生成的字节码无法预先处理,哪怕他是jdk的核心类库。

动态注入

如果使用了-javaagent加入的监控修改了字节码会是什么表现呢?
我们使用了字节码注入的agent demo。下面是个开源版本。
注入agent
这里一定要注意一个点,这个工具是通过asm做的,他可以打印方法的运行时间。**使用时要把asm的jar包换成一个对应jdk的版本,目前项目用的6,java11得升级。**否则你会发现神奇的错误,那个错误妙不可言。

java -Xbootclasspath/a:asm-8.0.1.jar:asm-analysis-8.0.1.jar:asm-commons-8.0.1.jar:asm-tree-8.0.1.jar  -javaagent:trace-0.0.1-SNAPSHOT-agent.jar=Test -XX:AOTLibrary=./libtest.so -XX:+PrintAOT AotTest

通过这个启动参数。我这里只注入我的一个测试类。看看他的方法打印的结果,以及aot的表现。
加agent日志

    179    1     aot[ 1]   AotTest.lambda$main$0(II)I
    179    2     aot[ 1]   AotTest.<init>()V
this is TestB 
[Ljava.lang.String; main cost 0(这里是agent输出,单位是毫秒)

不加agent

     11    1     loaded    ./libtest.so  aot library
    107    1     aot[ 1]   AotTest.lambda$main$0(II)I
    107    2     aot[ 1]   AotTest.<init>()V
    107    3     aot[ 1]   AotTest.main([Ljava/lang/String;)V
    108    4     aot[ 1]   TestB.<init>()V
    108    5     aot[ 1]   TestB.main([Ljava/lang/String;)V
this is TestB

结果发现testB不见了,也就是说agent注入改造后的类是无法使用aot的效果的。

实战编译math3

我们下面编译math3来展示常用的方式。
我们先尝试编译

jaotc  --output libmath.so --jar commons-math3-3.6.1.jar

你会发现这个会报错。

Error: Failed compilation: org.apache.commons.math3.optim.nonlinear.scalar.noderiv.BOBYQAOptimizer.bobyqb([D[D)D: org.graalvm.compiler.core.common.PermanentBailoutException: Too many loops in method
Error: Failed compilation: org.apache.commons.math3.optimization.direct.BOBYQAOptimizer.bobyqb([D[D)D: org.graalvm.compiler.core.common.PermanentBailoutException: Too many loops in method

这个情况是我们比较常见的,aot现在还不能匹配所有的场景。我们最简单的就是去掉这个,保证我们编译成功。我们可以使用exclude来去掉不可编译选项。
编写一个文件命名随意,我这里用 exclude.txt,把不能编译的方法都做一下去除。

exclude org.apache.commons.math3.optim.nonlinear.scalar.noderiv.BOBYQAOptimizer.bobyqb([D[D)D
exclude org.apache.commons.math3.optimization.direct.BOBYQAOptimizer.bobyqb([D[D)D

这次尝试编译的话,我们使用–compile-commands把我们指定的规则加上去。

jaotc  --output libmath.so  --compile-commands  exclude.txt --jar commons-math3-3.6.1.jar

再次执行,可以生成对应的libmath.so。
exclude掉一些方法,只要那个不是什么热点方法,其实影响不会太大。我们只要保证大部分的,热点的代码,可以利用aot加速,程序的启动速度就会得到很大的提升。所以这里并不用太担心影响。
有exclude,所以同时也有compileOnly。目的就是比较好的选择出可以编译的选项。

常用参数

  --compile-for-tiered       Generate profiling code for tiered compilation

在上面介绍的一些参数外,一般编译时还加上面这个参数。这个参数上标注了以后可能会去除,说明那时候aot有更好的解决方案了。在没有对应的解决方案出来时,先都加着吧。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP