晚期(运行期)优化——HotSpot虚拟机内的即时编译器


首先,我们要知道以下概念
热点代码

就是会运行特别频繁的代码,会被编译成机器码。

将热点代码编译成机器码这个任务是由**即时编译器(后台运行期编译器)**完成的。

还有注意一点,即时编译器并不是必须的,但是衡量一款商用虚拟机优秀与否最关键的指标之一。

这一节,我们要完成以下几个问题:

  • 1.何Hotspot虚拟机要使用解释器和编译器并存的架构?
  • 2.为什么Hotspot实现了两个不同的即时编译器(C1、C2)
  • 3.程序什么时候使用解释器执行?什么时候使用编译器执行?
  • 4.哪些代码(热点代码)会被编译成本地代码?如何编译成本地代码?
  • 5.如何从外部观察即时编译器的编译过程和编译结果?

最后,需要注意一点:这一节指的编译器都是Hotspot的即时编译器,虚拟机也指HotSpot虚拟机


一、解释器与编译器

1.1 解释器与编译器的优势

对于问题1,我们就要说一下解释器和编译器各自的优点了。

  • 如果想快速启动和执行,解释器就很不错。但是随着时间的推移,使用编译器会获得更高的执行效率
  • 如果内存资源限制比较大,可以使用解释器节约内存。反之可以使用编译执行类提高执行效率
  • 解释器还可以充当编译器激进优化的逃生门。当激进优化发生问题时,可以通过逆优化退回到解释状态继续执行。

解释器和编译器的交互:

请求即时编译
逆优化
解释器
C1或C2

1.2 C1与C2

C1:Client Compiler
C2:Server Compiler
可以通过“-client”与“-server”参数去强制指定虚拟机运行在Client模式或Server模式。

扫描二维码关注公众号,回复: 4118629 查看本文章

1.3 混合模式、解释模式、编译模式

混合模式:解释器和编译器混合使用的模式
解释模式:全部代码使用解释方式执行,编译器不介入工作
编译模式:尝试让全部代码在编译方式下运行,实在不行,还是要采用解释方式执行

可以设置“-Xint”或“Xcomp”让编译器运行在解释模式或编译模式。

1.4 分层编译

为了在程序启动响应速度与运行效率之间达到最佳平衡,Hotspot虚拟机会逐渐启用分层编译的策略。对应问题2。

第i层 任务
0 程序解释执行,不开启性能监控功能,可出发第1层编译
1 也称为C1编译,将字节码编译为本地代码,进行简单、可靠的优化,如有必要将加入性能监控的逻辑
2 也称C2编译,也将字节码编译为本地代码,但会开启一些编译耗时比较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化

二、编译对象与出发条件

2.1 热点代码

对于问题3,4,什么时候进行解释执行,什么时候进行编译执行?热点代码就编译执行呗!热点代码有两类:

类型 编译对象
被多次调用的方法 编译对象就是整个方法
被多次执行的循环体 编译对象还是整个方法。虽然编译动作是有循环体触发的。这种编译方式是发生在方法执行过程中的,形象的称为栈上替换,即OSR

2.2 热点探测

热点探测,用于判断一段代码是否为热点代码。目前主要的热点探测技术有两种:

种类 说明
基于采样的热点探测 如果一个方法经常出现在线程的栈顶,那么它就是热点代码。但是,这种方式回受到线程阻塞的影响,进而得到非正常结果
基于计数器的热点探测 为每个方法,甚至代码块建立计数器,统计执行次数,当执行次数超过一定阈值就为热点代码。

2.3 HotSpot的基于计数器的热点探测方法

HotSpot为方法提供了两类计数器——方法调用计数器(统计方法调用次数)、回边计数器(统计方法中循环体执行的次数)。下面的计数器触发编译都是C1的,C2要复杂一些。
(1)方法调用计数器出发编译

Java方法入口
是否存在已编译版本
方法调用计数器值加1
两计数器值之和是否超过阈值
向编译器提交编译请求
以解释方式执行方法
Java方法返回
执行编译后的本地代码版本

需要注意的是,当超过一定的时间限度,如果方法的调用次数仍然不超过阈值,那么这个方法的调用计数器就会被减半,这就是方法的——半衰期

(2)回边计数器出发即时编译(疑问:编译对象是方法,而循环体的上一次执行应该保存下来,以便下一次执行时,在机器码中(方法)找到循环体的状态)

遇到回边指令
是否存在已编译版本
执行编译后的本地代码版本
Java方法返回
回边计数器加1
两技术器值之和是否超过阈值
以解释方法继续执行
调整回边计数器值,稍微降低一些,以便解释执行能够继续
//IntExe

注意:”调整回边计数器值,稍微降低一些,以便解释执行能够继续“这一步是要等待编译器输出编译结果的


三、编译过程

C1、C2的编译过程不一样。
(1)C1的编译过程——简单快速的三段式编译器

阶段 说明 平台相关
第一阶段 将字节码转换为高级中间代码 平台独立
第二阶段 从高级中间代码转换为低级中间代码 平台相关
第三阶段 使用线性扫描算法优化产生机器代码 平台相关

(2)C2的编译过程
C2相对于C1,代码质量提高了,可以减少本地代码的执行时间,从而抵消编译时间。所以也有些非服务端的应用选择使用C2模式的虚拟机运行。

四、查看及分析即时编译结果

后面有时间在写!!!

参考文献

周志明的《深入理解java虚拟机JVM高级特性与最佳实践》

猜你喜欢

转载自blog.csdn.net/wobushixiaobailian/article/details/83990753