JIT即时编译
Posted yangfei629
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JIT即时编译相关的知识,希望对你有一定的参考价值。
1、Java执行过程
Java文件通过javac静态编译为class文件
class文件有2种方式执行:解释执行、JIT即时编译后执行
通常情况下 默认解释器边解释边运行,但对于一些热点代码会首先编译为机器码,缓存起来,后续执行执行缓存的机器码即可,提升执行效率
2、热点代码
Java采用计数器方式确认是否是“热点”代码
a. 方法调用次数 (方法调用计数器)
一段时间内的执行次数,当超过一定的时间限度,若还是没有达到阈值,那么它的计数器会减少一半,此过程被称为热度衰减。这段时间称为“半衰周期”
Client 模式下默认阈值是 1500 次,
Server 模式下是 10000次,
这个阈值可以通过 -XX:CompileThreadhold 来人为设定
半衰周期通过-XX:CounterHalfLifeTime设定(单位秒,默认?),-XX:-UseCounterDecay可关闭半衰周期
b. 方法体内某个循环次数 (回边计数器),
这种情况也叫栈上替换(OSR编译),它没有半衰周期,因为就在一次方法调用中。
-XX:OnStackReplacePercentage 来间接调整阈值
在 Client 模式下, 公式为 方法调用计数器阈值(CompileThreshold)X OSR 比率(OnStackReplacePercentage)/ 100 。
其中 OSR 比率默认为 933,那么,回边计数器的阈值为 13995。
方法计数器:
回边计数器:
3、JIT编译优化
JIT编译优化
a. 公共子表达式消除
例:int d = ( c * b ) * 12 + a + ( a + b * c);
当这段代码经过虚拟机即时编译器后,他将进行如下优化:减少了栈上操作。
int d = E * 12 + a + ( a + E);
有肯还会进行另一种优化:代数化简
int d = E * 13 + a * 2;
b. 数组边界检查消除
如在数组访问发生在循环之中,如果编译期只要通过数据流分析就可以判断循环变量的取值范围永远在[0,foo.length)中,那在整个循环中就可以把数组的上下界检查消除,这可以节省很多次的条件判断。
c. 方法内联
d. 逃逸分析 带来的栈上替换、标量替换、锁消除
以上是关于JIT即时编译的主要内容,如果未能解决你的问题,请参考以下文章