一 HotSpot VM 设置程序执行方法
缺省情况下 HotSpot VM 是采用解释器与即时编译器并存的架构,当然开发人员可以根据具体的应用场景,通过命令显式地为 Java 虚拟机指定在运行时到底是完全采用解释器执行,还是完全采用即时编译器执行。
-
-Xint:完全采用解释器模式执行程序
-
-Xcomp:完全采用即时编译器模式执行程序。如果即时编译出现问题,解释器会介入执行。
-
-Xmixed:采用解释器+即时编译器的混合模式共同执行程序。
二 HotSpot VM中 JIT 分类
JIT 的编译器还分为了两种,分别是 C1 和 C2 ,在 HotSpot VM 中内嵌有两个 JIT 编译器,分别为 Client Compiler 和 Server Compiler,但大多数情况下我们简称为 C1 编译器 和 C2 编译器。开发人员可以通过如下命令显式指定 Java 虚拟机在运行时到底使用哪一种即时编译器。
-client:指定 Java 虚拟机运行在 Client 模式下,并使用 C1 编译器;
C1 编译器会对字节码进行简单和可靠的优化,耗时短。以达到更快的编译速度。
-server:指定 Jav a虚拟机运行在 Server 模式下,并使用 C2 编译器。
C2 进行耗时较长的优化,以及激进优化。但优化的代码执行效率更高。(使用C++)
三 C1 和 C2 编译器不同的优化策略
在不同的编译器上有不同的优化策略,C1 编译器上主要有方法内联,去虚拟化、冗余消除。
-
方法内联:将引用的函数代码编译到引用点处,这样可以减少栈帧的生成,减少参数传递以及跳转过程。
-
去虚拟化:对唯一的实现类进行内联。
-
冗余消除:在运行期间把一些不会执行的代码折叠掉。
C2 的优化主要是在全局层面,逃逸分析是优化的基础。基于逃逸分析在 C2 上有如下几种优化:
-
标量替换:用标量值代替聚合对象的属性值。
-
栈上分配:对于未逃逸的对象分配对象在栈而不是堆。
-
同步消除:清除同步操作,通常指 synchronized
四 分层编译策略——JVM C1 和 C2 都是会用到的
分层编译(Tiered Compilation)策略:程序解释执行(不开启性能监控)可以触发 C1 编译,将字节码编译成机器码,可以进行简单优化,也可以加上性能监控,C2 编译会根据性能监控信息进行激进优化。
不过在 Java7 版本之后,一旦开发人员在程序中显式指定命令“-server"时,默认将会开启分层编译策略,由 C1 编译器和 C2 编译器相互协作共同来执行编译任务。
五 总结
一般来讲,JIT 编译出来的机器码性能比解释器高。
C2 编译器启动时长比 C1 慢,系统稳定执行以后,C2 编译器执行速度远快于 C1 编译器。
六 实战——测试解释器模式和 JIT 编译模式
1 代码
/**
* 测试解释器模式和 JIT 编译模式
* -Xint : 8493ms
* -Xcomp : 986ms
* -Xmixed : 827ms
*/
public class IntCompTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
testPrimeNumber(1000000);
long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
}
public static void testPrimeNumber(int count) {
for (int i = 0; i < count; i++) {
//计算100以内的质数
label:
for (int j = 2; j <= 100; j++) {
for (int k = 2; k <= Math.sqrt(j); k++) {
if (j % k == 0) {
continue label;
}
}
//System.out.println(j);
}
}
}
}
2 测试
* -Xint : 8493ms
* -Xcomp : 986ms
* -Xmixed : 827ms