为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器,简称JIT编译器。注:JIT编译器并非虚拟机必备的,但却是体现虚拟机技术水平的标杆。
1、解释器与编译器
解释器:当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行。
编译器:编译执行能提高效率。
即:解释执行节约内存,编译执行提升效率。分为:C1、 C2两种编译器。
2、C1与C2
C1:将字节码编译成本地代码,进行简单、可靠的优化(局部优化)。
C2:将字节码编译成本地代码,会启动一些编译耗时较长的优化,甚至会进行一些不可靠的激进优化。
即:C1(Client Compiler)可获得更高的编译速度,C2(Server Compiler)可获得更好的编译质量。
3、“热点代码”的定位
在运行过程中会被即时编译器编译成“热点代码”的有两类:
a.被多次调用的方法;
b.被多次执行的循环体( OSR:On Stack Replacement:栈上替换)。
有两种探测方式判断“热点代码”:
a.基于采样的热点探测
b.基于计数器的热点探测:HotSpot虚拟机使用此模式。阈值设定:-XX:CompilerThreadhold。
4、C2(Server Compiler)详解
C2(Server Compiler)是专门面向服务器端的典型应用并为服务器的性能配置特别调整过的编译器,也是一个经过充分优化的编译器。它会执行所有的经典优化动作,如:无用代码消除、循环展开、消除公共子表达式等等。
5、编译优化技术详解
虚拟机设计团队几乎把对代码的所有优化措施都集中在了即时编译器之中;他们设计了很多的优化技术,下面部分举例说明:
初始代码:只是举例介绍,并非vm真正按照这种方式做的
/**
*
* @author zhengchao
*/
class B {
public static int value;
public B(int value){
B.value = value;
}
final int get(){
return value;
}
public static void main(String[] args){
B b = new B(9);
foo(b);
}
public static void foo(B b){
int y = b.get();
int z = b.get();
int x = y+z;
System.out.println(x);
}
}
首先进行方法内联:不在调用get方法,直接.value。
class B {
public static int value;
public B(int value){
B.value = value;
}
final int get(){
return value;
}
public static void main(String[] args){
B b = new B(9);
foo(b);
}
public static void foo(B b){
int y = b.value;
int z = b.value;
int x = y+z;
System.out.println(x);
}
}
再进行冗余代码的消除:z的赋值无需用上述的方式:
class B {
public static int value;
public B(int value){
B.value = value;
}
final int get(){
return value;
}
public static void main(String[] args){
B b = new B(9);
foo(b);
}
public static void foo(B b){
int y = b.value;
int z = y;
int x = y+z;
System.out.println(x);
}
}
继而进行无用代码的消除:
class B {
public static int value;
public B(int value){
B.value = value;
}
final int get(){
return value;
}
public static void main(String[] args){
B b = new B(9);
foo(b);
}
public static void foo(B b){
int y = b.value;
int x = y+y;
System.out.println(x);
}
}
以上仅仅只是举例方便大家理解优化的思路。下面详细介绍具体的一些方法。
a、公共子表达式消除:计算过的表达式不再继续计算,前提计算的两个数值中途未发生变化。。。。
b、数组边界检查消除、自动装箱消除、安全点消除、消除反射等等:为了不必要的检查浪费判断时间。。。。如下这种优化:
if(b!=null){
return b;
} else {
throw new NullPointException();
}
优化后:
try{
return b;
} catch(..){
..
}
c、方法内联。。。。
d、逃逸分析:前沿技术,详细可参考《深入理解java虚拟机》。。。
优化的技术还有很多,在此不做一一陈述。