0%

HotSpot原理指南-JIT触发条件

前言

通过前面我们知道,对于每个方法,HotSpot都维护两个计数器

  • Invocation Counter:方法被调用次数,每被调用一次都会+1
  • BackEdge Counter:专业的说法就是字节码在执行时的回跳次数。通俗点说就是,在For或者While循环中,每执行一次,都会+1。

并且我们知道对于一个方法,JIT有两种不同的编译方式

  • 完整的原方法编译,就是把原本的方法逻辑进行编译。入参和运行结果和解释运行都是一致的。
  • OSR编译,OSR后的方法入参以及运行流程和原方法有较大差异。

很自然得我们就会想到,其实计数器和编译方式之间是有对应关系的。

  • Invocation Counter -> 完整的原方法编译
  • BackEdge Counter -> OSR编译

当对应的方法计数器达到一定的次数,就会触发响应的编译

编译流程图

完整的编译流程如下:

注:该图引自R大的JVM分享PPT,如有侵权,请联系我删除

图中的流程非常的清晰,这里提几个小点:

  • 问:对于同一方法,是否两种编译方式都可能会执行?

    答:是的,而且两种代码可能同时被运行,但是正常情况下,只要运行的够久,都会运行完整的原方法编译后的代码。

  • 问:具体哪种编译方式先触发?

    答:其实无法确定,看哪个计数器先达到阈值

触发阈值

可能你还想更直观的了解下两个计数器的触发阈值到底是多少。

在HotSpot源码中,有这样两个参数:

  • intx CompileThreshold = 10000

    globals.hpp > ”number of interpreted method invocations before (re-)compiling”

  • intx BackEdgeThreshold = 100000

    globals.hpp > “Interpreter Back edge threshold at which an OSR compilation is invoked”

数值可能根据不同的发行版本略有不同,上面的数值是JDK7版本中的。

那么你可能以为

  • 当Invocation Counter > Compile Threshold时,就会触发原来方法的JIT
  • 当BackEdge Counter > BackEdge Threshold时,就会触发方法的OSR编译

但是事实并不是如此。

问题出在哪儿呢?难道官方的定义还会有错吗?

是的,问题出在BackEdgeThreshold上,虽然HotSpot中确实定义了该参数,描述中似乎也证实了该参数的作用,但是这个参数并没有实际使用过。

对于BackEdgeThreshold的计算,是另外一套公示。

1
2
3
4
5
6
7
if (ProfileInterpreter) {
InterpreterBackwardBranchLimit =
(CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100;
} else {
InterpreterBackwardBranchLimit =
((CompileThreshold * OnStackReplacePercentage) / 100) << number_of_noncount_bits;
}

首先解释下ProfileInterpreter参数,这个参数也是在HotSpot中定义的,之前在文章HotSpot原理指南-C1和C2介绍中也讲解过,就是是否在运行时收集方法的Profile信息,这个字段在Server模式默认是开启的。

所以大部分情况下,除非你的计算机比较老,都会根据第一个公示进行计算

(CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100

其中OnStackReplacePercentage默认值是140,InterpreterProfilePercentage默认值是33。

由此我们可以计算出真实的BackEdge Invocation阈值大概是10700左右。

衰减

假如方法计数器不会根据时间进行衰减的话,那么只要服务器运行的时间足够长,再罕见被调用的函数,也会触发到阈值,然后被JIT编译。

这显然是不合理的,因为我们知道JIT后的机器码数据,还是会保存在内存中的,这样相当于一段逻辑在内存中又保存了字节码,又保存了一份机器码,十分的浪费内存。

所以对于Invocation Counter而言,经过一段时间,个数就会进行减少。

具体的减少逻辑,读者有兴趣的可以自己去探索。

但是注意:对于BackEdge Counter,是不会作衰减的。