Java Agent 嵌码 对 JIT 方法内联的影响

在一次面试中谈论到Java agent的时候,涉及到了Java agent 和 JIT 相互关系和影响,当时并没有表述清楚,特此写下次笔记。以后再开发 Java Agent 的时候 也应该更加注意 JIT 这块的内容。

Java Agent 嵌码是非常灵活的,可以在任何的位置进行打点嵌码,JIT 本身是为了提高Java 执行效率,两者要处理好,不然Java Agent 很可能影响到JVM JIT的工作。

JIT 中 方法内联机制和Java Agent 嵌码关系最为密切,以下重点就是 JIT 方法内联。

JIT 方法内联

JIT 的执行过程

方法内联的原理

方法内联就是把被调用方函数代码”复制”到调用方函数中,来减少因函数调用开销的技术。

我们写一个简单的两数相加程序,被内联前的代码:

1
2
3
4
5
6
7
private  int  add4(int x1, int x2, int x3, int x4) { 
return add2(x1, x2) + add2(x3, x4);
}

private int add2(int x1, int x2) {
return x1 + x2;
}

运行一段时间后JVM会把add2方法去掉,并把你的代码翻译成:

1
2
3
private int add4(int x1, int x2, int x3, int x4) {  
return x1 + x2 + x3 + x4;
}

方法内联的条件

JVM会自动的识别热点方法,并对它们使用方法内联优化。那么一段代码需要执行多少次才会触发JIT优化呢?通常这个值由-XX:CompileThreshold参数进行设置:

  • 使用client编译器时,默认为1500;

  • 使用server编译器时,默认为10000;

但是一个方法就算被JVM标注成为热点方法,JVM仍然不一定会对它做方法内联优化。其中有个比较常见的原因就是这个方法体太大了,分为两种情况。

  • 如果方法是经常执行的,默认情况下,方法大小小于325字节的都会进行内联(可以通过-XX:MaxFreqInlineSize=N来设置这个大小)

  • 如果方法不是经常执行的,默认情况下,方法大小小于35字节才会进行内联(可以通过-XX:MaxInlineSize=N来设置这个大小)

Java Agent 和 JIT 方法内联的相互影响

JIT的方法内联是否会影响到 Java Agent 进行嵌码?

首先答案是不会影响的,Java Agent 会正常的进行嵌码。

在上述的原理说明中,add2 方法被 Jvm 优化掉了,如果Java Agent 嵌码就需要知道嵌码的类的名称和方法的名称,本来指定的嵌码的方法名称是 add2,但是现在这个方法不存在了,那如何嵌码成功? 不会产生影响的原因是 agent 嵌码时机在JTI之前。

在上述的执行过程中 java 代码执行 javac 编译的时候,方法并没有优化,class中还是原始方法,add2方法还是存在的。处理流程如下:

Java Code ->(执行JavaC) -> Class 文件 -> (JVM 加载 Class 时候 Agent 执行嵌码)-> (满足条件执行 JIT)

在 Agent 嵌码成功后,如果 JVM 要执行 JIT 方法内联,Agent嵌入的代码会一同执行方法内联,最后Agent 代码实际上是在 add4 中执行了。

Java Agent 嵌码是否会影响到 JVM JIT方法内联?

答案是会的。

在上述的 JIT 方法内联的条件中其中有一个条件就是方法体积的大小,如果 Java Agent 嵌入代码,肯定会增加方法的体积,如果超出设置的阈值,此方法就不会再执行JIT。

Java Agent 监控的方法,应该有一定的业务逻辑,比如上述的 add 方法,本身是没有太大的监控必要,如果监控的方法原本体积就比较大,不会执行 JIT ,那么影响还是比较小的。

Apptalking Agent JIT 监控优化

Apptalking Agent 有热点代码学习功能,这些热点代码中可能存在上述的 add 类型的简单方法,Apptalking Agent 会进行过滤,这类的方法会被强制拒绝监控 , 从而避免影响JVM JIT功能。

一个方法满足以下的全部条件会被标示为简单方法而放弃监控。

  • 方法类型为private方法
  • 方法中的指令数量不能超过10 个。(通过指令数量而没有通过体积)
  • 方法中不存在跳转指令。
  • 方法中不存在调用方法的指令。
  • 方法中不存在有锁相关的指令。

如果文章存在疏漏,欢迎大家指正。

参考《JIT Optimizations – Method Inlining