0%

即时编译器

即时编译器

当虚拟机发现某个方法或代码块的运行特别频繁时,会把这些代码认定为热点代码,为了提高热点代码的执行效率,在运行时虚拟机会将这些代码编译成与本地平台无关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器(Just In Time Compiler,简称JIT编译器)

在HotSpot中采用了解释器和编译器并存的架构,称为混合模式

使用java -version可以看到

1
2
3
4
java -version
java version "1.8.0_261"
Java(TM) SE Runtime Environment (build 1.8.0_261-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, mixed mode)

如果想要强制使用解释模式,使用参数-Xint

1
2
3
4
java -Xint -version
java version "1.8.0_261"
Java(TM) SE Runtime Environment (build 1.8.0_261-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, interpreted mode)

如果想要强制使用编译模式,使用参数-Xcomp

1
2
3
4
java -Xcomp -version
java version "1.8.0_261"
Java(TM) SE Runtime Environment (build 1.8.0_261-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, compiled mode)

热点探测

判断一段代码是不是热点代码,是不是需要触发即时编译,这种行为称为热点探测,主要的热点探测判定方式有两种

  • 基于采样的热点探测:该方法虚拟机会周期性的检查各个线程的栈顶,如果发现某个或某些方法经常出现在栈顶,那这个方法就是热点方法

    优点:实现简单、高效,可以很容易的获取方法调用关系

    缺点:很难精确地确认一个方法的热度,容易受到线程阻塞或别的因素的影响而扰乱热点探测

  • 基于计数器的热点探测:该方法虚拟机会为每个方法建立计数器,统计方法的执行次数,如果超过阈值则是热点方法(HotSpot采用的该种方式),阈值是在Client模式下是1500次,在Server模式下是10000次,可以通过-XX:CompileThreshold设定

    优点:统计结果更加精确和严谨

    缺点:实现麻烦,需要为每个方法建立并维护计数器,而且不能直接获取到方法的调用关系

当一个方法被调用时,会先检查该方法是否存在被JIT编译过的版本,如果存在,则优先使用编译后的本地代码来执行;如果不存在已被编译过的版本,则将此方法的调用计数器值加1,然后判断方法调用计数器与回边计数器之和是否超过方法调用计数器的阈值,如果已超过阈值,那么将会向即时编译器提交一个该方法的代码编译请求

参数配置

  • -XX:-UseCounterDecay 关闭热度衰减,默认是开启热度衰减,超过一段时间限度,如果方法的调用次数仍然不足以让它提交给即时编译器编译,那么这个方法的调用计数器就会被减少一半,该方式称为方法调用计数器的热度衰减,这个时间限制称为半衰周期。如果关闭热度衰减,那么只要系统运行时间足够长,绝大部分方法都会被即时编译器编译
  • -XX:CounterHalfLifeTime 设置半衰周期时间,单位秒
  • -XX:CompileThreshold 方法调用计数器阈值
  • -XX:BackEdgeThreshold 回边计数器阈值
  • -XX:OnStackReplacePercentage OSR比率