14 HotSpot虚拟机将字节码编译为机器码的过程
目录
特别说明:
-
本章内容基于HotSpot虚拟机:
- 编译器指HotSpot内置的即时编译器
- 虚拟机指HotSpot
-
机器码:能够被被当前机器直接执行的代码,机器属于某个平台:SPARC、x86-AMD64、ARMv8-AArch64
1 广义理解:解释执行与编译执行
阅读原文2天,我仍然没理解 什么是解释执行,跟编译执行有什么不同。我尝试从书籍原文和行业规范等方向去查找资料,可是效果不佳。无奈,只能找一篇看起来还算正规的文章,以不思考通篇接受的方式,来帮助自己理解解释执行。这小节内容整理自:3分钟搞懂什么是编译执行和解释执行
2 HotSpot虚拟机基本介绍
- 它是Sun/OracleJDK和OpenJDK中的默认Java虚拟机,也是目前使用范围最广的Java虚拟机,首次被应用在JDK 1.3;
- 内置有编译器和执行器,采用解释器与编译器并存的运行架构
- 对比其他虚拟机,核心技术有:热点代码探测技术
3 为何HotSpot虚拟机要使用解释器与即时编译器并存的架构?
-
HotSpot执行字节码三种方式:
- 解释执行:解释器逐条执行字节码指令,或者轻度优化字节码后再执行
- 编译执行:即时编译器先对字节码指令流深度优化,编译成机器码后再执行。
- 混合模式:解释器和编译器协同执行
-
解释器和编译器如何协同工作:
- 程序启动时,先启用解释器,省去编译的时间,立即运行。
- 程序启动后,启用编译器,把越来越多的代码编译成本地代码,这就减少解释器的中间损耗,获得更高的执行效率。
- 如果编译器优化失败,还能退回解释器执行【这叫逆优化】
-
协同目的:
兼顾程序响应时间与执行性能,而且无须等待本地代码输出才能执行程序,即时编译的时间压力也相对减小,这样有助于引入更复杂的代码优化技术,输出质量更高的本地代码。
4 为何HotSpot虚拟机要实现两个(或三个)不同的即时编译器?
-
内置了三个即时编译器:
- 2个传统的:客户端编译器(C1)、服务端编译器(C2),
- 1个JDK10出现的:Graal编译器(长期目标是代替C2)
-
解释器搭配一个编译器来工作:
- 默认:HotSpot根据自身版本与宿主机的硬件性能自动选择编译器
- 指定:使用 -client 或 -server参数来指定编译器
-
目的:因为不同的编译器,优化的深度不一样,用户可以根据程序特点来选择
5 程序何时使用解释器执行?何时使用编译器执行?
-
HotSpot工作模式:
- 默认采用混合模式
- 用 -Xint强制使用解释模式:编译器不工作,全部指令都使用解释方式执行
- 用 -Xcomp强制使用编译模式,优先采用编译方式执行程序,但是解释器仍然要在编译无法进行的情况下介入执行过程
- 不同参数运行结果:
-
引入分层编译原因:
- 即时编译器越优化,耗时越长
- 编译器优化时,解释器要替编译器收集性能监控信息,反倒影响解释执行阶段的速度
- 兼顾程序启动响应速度与运行效率之间达到最佳平衡,引入分层编译
-
分层编译层次:
- 第0层。纯解释执行,且解释器不开启性能监控功能
- 第1层。C1将字节码编译为本地代码来运行,进行简单、可靠优化,不开启性能监控。
- 第2层。C1执行,仅开启方法及回边次数统计等有限的性能监控功能
- 第3层。C1执行,开启全部性能监控,除了第2层的统计信息外,增加收集 分支跳转、虚方法调用版本等统计信息。
- 第4层。C2将字节码编译为本地代码,对比C1,C2会启用更多编译耗时更长的优化,并根据性能监控信息进行一些不可靠的激进优化
6 哪些程序代码会被编译为本地代码?如何编译本地代码?
-
即时编译器编译的目标是热点代码:(以方法为单位)
- 被多次调用的方法
- 被多次执行的循环体
-
客户端编译器的三段式编译过程:
-
服务端编译器的编译过程:
- 比客户端模式进行更深入的优化:无用代码消除、循环展开、循环表达式外提、消除公共子表达式、常量传播、范围检查消除、空值检查消除;不稳定的预测性激进优化:守护内联、分支频率预测
- 采用全局图着色寄存器分配器
- 它更慢,但是输出代码的质量更高
-
即时编译目的
- 将字节码翻译为机器码 【基本、简单的需求】
- 代码优化【核心、关键的需求】
7 如何从外部观察到即时编译器的编译过程和编译结果?
算了吧,太复杂。
8 总结
回归主题,HotSpot虚拟机将字节码编译为机器码过程,如下图所示:
字节码转机器码补充说明:
- HotSpot预先写好所有字节码指令对应的汇编命令函数集,以字节码指令为key,函数为value方式保存
- HotSpot的模板解释器根据字节码指令查找到对应的汇编命令函数【查表方式】,不同平台的汇编器将这些汇编命令翻译成各自平台的机器码。
综上,编译过程总结过:原始字节码-->HotSpot优化字节码-->优化后的字节码翻译成机器码-->以编译执行方式运行程序。