菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
88
0

JVM的编译方式及运行效率

原创
05/13 14:22
阅读数 3370

JVM的编译方式及运行效率

Q:JVM采用了什么编译方式?
A:JVM的编译方式分为前端编译和后端编译,部分静态提前编译(AOT)

前端编译

简介

由于JVM的输入为字节码(.class文件),而我们的编程输出的是自然语言(.java文件),所以就需要一种将我们的输出(.java文件)转换成JVM输入(.class文件)的编译工具,它就是前端编译。
常见的前端编译即为JDK自带的Oracle的javac工具

过程

常见的javac编译过程大概分为了四个阶段。
第一阶段:词法分析。
第二阶段:语法分析。
第三阶段:语义分析。
第四阶段:字节码生成。

后端编译

从硬件视角上来看,JAVA字节码(.class)无法直接被底层硬件执行,需要不同平台的虚拟机给编译成各自平台适用的机器码。这个编译过程便是JVM的最大的功能之一。也正是这个功能保证了JAVA语言的跨平台的特性。

  1. 解释执行

顾名思义,就是逐条的将字节码翻译成机器码并执行。比如成同声传译,边听别写,解释执行便是边解释边执行。

  1. JIT

即时编译(Just In Time compilation),指在运行时,JVM将“热点方法”(class字节码)全部编译成机器码后在执行。

  1. 混合模式
类型 优点 缺点
解释执行 无需等待 执行速度较慢
JIT 执行效率较高 (程序执行符合二八定律) 1、搜集监控信息影响程序运行 2、编译程序信息占用程序运行时间(例如程序启动变慢) 3、编译机器码占用内存

JVM结合两者的优缺点,综合了两种编译方式的优点,采用了混合模式。HotSpot默认采用了混合模式,它先解释执行字节码,然后将其中反复执行的代码,以方法为单位进行及时编译。

静态提前编译(AOT)

在程序执行前,提前将java代码翻译成本地代码,一边在程序运行时直接调用本地代码。

AOT 编译器从编译质量上来看,肯定比不上 JIT 编译器。其存在的目的在于避免 JIT 编译器的运行时性能消耗或内存消耗,或者避免解释程序的早期性能开销。

在运行速度上来说,AOT 编译器编译出来的代码比 JIT 编译出来的慢,但是比解释执行的快。而编译时间上,AOT 也是一个始终的速度。所以说,AOT 编译器的存在是 JVM 牺牲质量换取性能的一种策略。就如 JVM 其运行模式中选择 Mixed 混合模式一样,使用 C1 编译模式只进行简单的优化,而 C2 编译模式则进行较为激进的优化。充分利用两种模式的优点,从而达到最优的运行效率。

Q:JVM的运行效率
A:HotSpot充分利用了各编译方式的优缺点,使JVM的运行效率达到最高。

上图是默认和使用命令调用不同的编译模式

对程序来说,也符合二八定律,即百分之二十的代码占用了百分之八十的计算资源。对于大部分的不常用的代码,我们我们无需耗费资源对其进行编译处理,只需要在执行时采用解释执行的方式即可;而对于百分之二十的常用的代码,我们可以采用JIT的方式,将其即时编译成机器码,这样在执行时的效率就能达到最高。

即时编译的运行效率,理论上可以超过静态编译的,相对于静态编译,即时编译可以保存一些运行时信息,(例如接口下的实现类,静态编译需要遍历所有的实现类来找到目标类,而即时编译所对应的就是对应的实现类)

C1、C2、Graal编译器

在采用即时编译的策略上,HotSpot也分为不同的做法,分别为较为缓和的C1编译器和较为激进的C2编译器,以及在JDK10中被引入的实验性质的Graal编译器。

引入了多个编译器,便是应对更加复杂的程序,在运行时间和运行效率中做取舍。

C1编译器又被称为Client编译器,编译时间相对较短,优化比较简单,常见的是启动的更快。

C2编译器又被称为Server编译器,编译时间相对较长,优化方式比较复杂和全面,优化后的代码执行效率更高。

C2的优化对比C1体现在两方面,一方面是进行了更多更全面的优化,另一方面是面对同一种优化采用不同的算法。

分层编译

从JDK7开始,HotSpot默认采用了分层编译的方式,“热点方法”会先被C1编译,“热点方法”的“热点”会被C2编译。

达到热点代码是通过热点算法来进行统计的,而分层编译的热点阈值又不同默认是的达到2k进入C1,达到15k进入C2(C1>2k, C2>15k)。

热点代码有两种算法,基于采样的热点探测和基于计数器的热点探测。一般采用的都是基于计数器的热点探测。基于计数器的热点探测又有两个计数器,方法调用计数器(热度衰减机制),回边计数器(OSRP计算公式 OnStackReplacePercentage),他们在C1和C2又有不同的阈值。

在运行时,解释执行和即时编译会同时进行,编译完成后的机器码会在下次执行时替代解释执行。

HotSpot 的即时编译是放在额外的编译线程中进行的。HotSpot 会根据 CPU 的数量设置编译线程的数目,并且按 1:2 的比例配置给 C1C2 编译器。

参考

  1. 《极客时间-深入拆解虚拟机-郑雨迪》
  2. Java三种编译方式 - CSDN
  3. HotSpot原理指南-个人博客
  4. hotspot热点代码探测-知乎

发表评论

0/200
88 点赞
0 评论
收藏
为你推荐 换一批