我们知道,Java 是解释执行的,可是解释执行毕竟还是有点慢的,这也使得 Java 一直被认为是效率低下的语言……,不过随着即时编译技术的发展,Java 的运行速度得到了很大的提升,在本篇文章中,我们将会对 Java 的运行期优化,也就是即时编译 (Just In Time, JIT) 时进行的优化进行详细的讲解,我们先来看看什么是即时编译。
什么是即时编译?
我们主要通过以下 5 个问题来了解 HotSpot 虚拟机的即时编译器。
-Xint
,编译器完全不工作;-Xcomp
,当编译器编译失败时,解释执行还是会介入的。分层编译就是根据编译器编译、优化的规模与耗时,划分出不同的编译层次,在代码运行的过程中,可以动态的选择将某一部分代码片段提升一个编译层次或者降低一个编译层次。
C1 与 C2 编译器会同时工作,许多代码可能会被多次编译。
目的: 在程序的启动响应时间和运行效率间达到平衡。
编译层次的划分:
我们发现,判断热点代码的一个要点就是: 多次执行 。那么虚拟机是如何知道一个方法或者一个循环体被多次执行的呢?
-XX: -UseCounterDecay
(此时方法计数器统计的是方法被调用的绝对次数);-XX: CounterHalfLifeTime
(单位是秒);-XX: OnStackReplacePercentage
(OSR比率)
回边计数器的阈值 = 方法调用计数器阈值 * OSR比率 / 100
;回边计数器的阈值 = 方法调用计数器阈值 * ( OSR比率 - 解释器监控比率 ) / 100
;虚拟机在代码编译未完成时会按照解释方式继续执行,编译动作在后台的编译线程执行。
禁止后台编译:-XX: -BackgroundCompilation
,打开后这个开关参数后,交编译请求的线程会等待编译完成,然后执行编译器输出的本地代码。
Content:
如果一个表达式 E 已经计算过了,并且从先前的计算到现在,E 中所有变量值都没有发生变化,则 E 为公共子表达式,无需再次计算,直接用之前的结果替换。
在循环中使用循环变量访问数组,如果可以判断循环变量的范围在数组的索引范围内,则可以消除整个循环的数组范围检查
目的是:去除方法调用的成本(如建立栈帧等),并为其他优化建立良好的基础,所以一般将方法内两放在优化序列最前端,因为它对其他优化有帮助。
类型继承关系分析(Class Hierarchy Analysis,CHA)
用于确定在目前已加载的类中,某个接口是否有多于一种的实现,某个类是否存在子类、子类是否为抽象类等。
分析对象的作用域,看它有没有能在当前作用域之外使用:
-XX: +DoEscapeAnalysis
-XX: +EliminateAnalysis
-XX: +EliminateLocks
-XX: PrintEscapeAnalysis
-XX: PrintEliminateAllocations
原始代码:
static class B {
int value;
final int get() {
return value;
}
}
public void foo() {
y = b.get();
// ...do stuff...
z = b.get();
sum = y + z;
}
第一步优化: 方法内联(一般放在优化序列最前端,因为对其他优化有帮助)
目的:
public void foo() {
y = b.value;
// ...do stuff...
z = b.value;
sum = y + z;
}
第二步优化: 公共子表达式消除
public void foo() {
y = b.value;
// ...do stuff... // 因为这部分并没有改变 b.value 的值
// 如果把 b.value 看成一个表达式,就是公共表达式消除
z = y; // 把这一步的 b.value 替换成 y
sum = y + z;
}
第三步优化: 复写传播
public void foo() {
y = b.value;
// ...do stuff...
y = y; // z 变量与以相同,完全没有必要使用一个新的额外变量
// 所以将 z 替换为 y
sum = y + z;
}
第四步优化: 无用代码消除
无用代码:
- 永远不会执行的代码
- 完全没有意义的代码
public void foo() {
y = b.value;
// ...do stuff...
// y = y; 这句没有意义的,去除
sum = y + y;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。