zl程序教程

您现在的位置是:首页 >  其它

当前栏目

1.2 tiered compilation(分层编译)

编译 1.2 分层 Compilation
2023-09-11 14:20:29 时间

五个级别

  前文讲过,编译器分c1和c2两种,c1适合客户端,启动速度快,但是编译后的代码质量不高。C2适合服务端,启动速度慢,占用内存高,但是编译后的代码质量高,执行效率高。在JDK8以前,使用-client可以激活C1编译器,-server可以激活C2编译器。但是JDK8及以后的版本这个就没用了。
  那有没有中间方案呢?JDK7开始,出现了混合模式编译,也就是分层编译技术。分层编译技术不仅Java有,Java的竞争对手.Net也有分层编译技术。
  Java的分层编译将编译定义为五个级别:

级别策略
0解释器执行
1无任何监控模式的C1编译器
2带方法调用和回边计数器的C1编译器
3完全监控模式(MDO)的C1编译器
4C2编译器

  对于level 1~3,很多博文没解释清楚,我解释一下。解释器是肯定带方法调用和回边计数器的。但是C1编译器可以带,也可以不带。所以level 1,level 2和level 3。性能最高的是level 1,因为不监控任何数据,性能最差的是level 3。所以他们的性能是level 4 > level 1 > level 2 > level 3 > level 0。但是因为level 1没有任何监控,所以它不可能有触发机制到达level 4,除非反优化,level 1将是终态。
  更需要注意的编译级别的切换不是整个虚拟机的级别切换,而是某个方法的级别切换。在虚拟机运行过程中,一个程序流程,调用了很多方法,这里面有些方法是解释器运行,有些是编译器运行。所以编译级别是方法的属性,也不是线程的属性,更不是虚拟机的属性。

级别切换

  通常情况: 0 → 3 → 4 0 \to 3 \to 4 034
  C2队列满: 0 → 2 → 3 → 4 0 \to2\to 3 \to 4 0234。这里我解释一下。因为level 3的目的是完全监控,然后用监控数据去进行C2编译。因为C2队列满了,所以不仅level4的方法不能再增加,level 3的方法也不能继续增加,所以level 0就直接编译为level 2。等C2队列空闲的时候,level 2的方法又调整为level 3。
  C2队列满,已经在队列里的变成2: 3 → 2 3\to2 32。这里我解释一下,因为C2队列满了,所以已经在队列里的level 3临时改变目标,编译为level 2。
  禁用了C2或者方法体过于简单: 0 → 2 → 1 0 \to 2 \to 1 021
  禁用了C2或者方法体过于简单: 0 → 3 → 1 0 \to 3 \to 1 031
  解释器完全监控模式: 0 → 4 0 \to4 04
  反优化: ( 1 , 2 , 3 , 4 ) → 0 (1,2,3,4)\to0 (1,2,3,4)0
  为此,我画了一张图:
在这里插入图片描述