您的位置 首页 java

JIT即时编译(基础概念)

在 中我们已经讲述了Java编译中的前端编译(javac),今天我们就看一下后端编译。

1. 为什么需要后端编译(JIT)

当我们的 字节码 文件被 虚拟机 加载过后,其实就可以解释执行,也就是说即使没有后端编译我们的Java程序也可以运行。之所以需要后端编译是因为解释执行虽然会提高程序的启动速度,但当程序稳定运行以后,运行速度不会再有所改善。计算机的世界与天下武功一样,唯快不破, 为了不断提高我们的程序运行速度 ,我们需要在程序运行过程中对特定代码进行编译,将本地代码编译成机器可以直接识别的机器代码。

2. HotSpot虚拟机的JIT

HotSpot VM中集成了两种编译器,Client Compiler和Server Compiler,它们的作用也不同。Client Compiler注重启动速度和局部的优化,Server Compiler则更加关注全局的优化,性能会更好,但由于会进行更多的全局分析,所以启动速度会变慢。两种编译器有着不同的应用场景,在虚拟机中同时发挥作用。

2.1 Client Compiler

HotSpot VM中带有一个Client Compiler C1编译器,它主要做以下事情:

  • 局部简单可靠的优化,比如字节码上进行的一些基础优化,方法内联、常量传播等,放弃许多耗时较长的全局优化。
  • 将字节码构造成高级中间表示(High-level Intermediate Representation,以下称为HIR),HIR与平台无关,通常采用图结构,更适合 JVM 对程序进行优化。
  • 最后将HIR转换成低级中间表示(Low-level Intermediate Representation,以下称为LIR),在LIR的基础上会进行寄存器分配、窥孔优化(局部的优化方式,编译器在一个基本块或者多个基本块中,针对已经生成的代码,结合CPU自己指令的特点,通过一些认为可能带来性能提升的转换规则或者通过整体的分析,进行指令转换,来提升代码性能)等操作,最终生成机器码。

2.2 Server Compiler

Server Compiler主要关注一些编译耗时较长的全局优化,甚至会还会根据程序运行的信息进行一些不可靠的激进优化。这种编译器的启动时间长,适用于长时间运行的后台程序,它的性能通常比Client Compiler高30%以上。目前,Hotspot虚拟机中使用的Server Compiler有两种:C2和Graal。

关于Client Compiler和Server Compiler后面我会单独写一下具体的编译过程。

3. 分层编译

即时编译器编译代码需要时间,一般编译出优化程度更高的代码(影响程序启动响应速度,但是会提高运行效率),编译会花费更多的时间。为了在程序启动响应速度和运行效率之间达到平衡,HotSpot虚拟机采用分层编译,分层编译的思想将JVM的执行状态划分为5层:

  • 第1层:解释执行
  • 第2层:执行不带Profiling(收集反应执行状态的数据)的C1本地代码
  • 第3层:执行带方法调用次数和回边调用次数Profiling的C1本地代码
  • 第4层:执行所有Profiling的C1本地代码
  • 第5层:执行C2本地代码

3.1 编译条件

在程序运行过程中,热点代码会触发编译,热点代码有以下两类:

  • 被多次调用的方法
  • 被多次执行的循环体

热点代码通过热点探测的方式进行判定,判定的方式大约有两种:

  • 基于采样的热点探测:虚拟机周期性检查线程的栈顶,如果某个方法经常出现在栈顶,那么该方法即为热点方法。这种实现方式简单高效,但是精确度不够,一些阻塞的方法会被误判为热点方法。
  • 基于 计数器 的热点探测:对每个方法(甚至方法块)建立计数器,执行次数超过一定的 阀值 就被判定为热点方法。

Hotspot虚拟机采用的是基于计数器的热点探测,虚拟机为每个方法准备了两类计数器:

  • 方法调用计数器
  • 回边计数器

在分层编译开启的情况下,触发编译由以下条件来判断:

  • 方法调用次数大于由参数-XX:TierXInvocationThreshold指定的阀值乘以系数
  • 方法调用次数大于由参数-XX:TierXMINInvocationThreshold指定的阀值乘以系数,并且方法调用次数和循环回边次数之和大于由参数-XX:TierXCompileThreshold指定的阀值乘以系数时

以上两个条件满足其中一个即可触发即时编译,系数会由虚拟机根据当前编译的方法数以及编译线程数动态调整。

公式如下:

 // i为方法调用计数器记录的方法调用次数
// b为回边计数器记录的循环回边次数
i > TierXInvocationThreshold * s || (i > TierXMINInvocationThreshold * s && i + b > TierXCompileThreshold * s)
  

本期的JIT即时编译介绍到这,我是shysh95,我们下期再见!!!

文章来源:智云一二三科技

文章标题:JIT即时编译(基础概念)

文章地址:https://www.zhihuclub.com/190284.shtml

关于作者: 智云科技

热门文章

网站地图