java类得执行机制分为字节码解释执行和编译为机器码执行,后者又分为client compiler 和server compiler
1、字节码解释执行
JVM是一种中间代码的方式 ,在执行时候,JVM有自己的一套指令,JVM采用invokestatic、invokevirtual、invokeinterface、invokespecial来查找执行不同的方法。
invokestatic会调用static方法,invokevirtual会调用对象实例的方法,invokeinterface会调用接口的方法,invokespecial会调用私有的方法和编译之后<init>方法,此方法为对象实例化的初始化方法,如下面的代码:
public class Demo{
public void execute{
A.execute();//调用invokestatic
A a =new A();//调用invokespecial
a.am();//调用invokevirtual
IB b = new B();//调用invokespecial
b.bm();//调用invokeinterface
}
}
public class A{
public static String execute(){
return "A";
}
public am(){
return "am";
}
}
public interface IB{
public String mb();
}
public class B implements IB{
public String mb{
return "mb";
}
}
以上是四种指令对应方法的情况。
2、编译执行
1)client compiler(C1)
client compiler又称为C1,只做少量性能开销比较高的优化,占内存比较小,适合桌面应用程序,其中采用的优化方式主要有方法内联、冗余消除、去虚拟化等。
①方法内联
通常一个业务逻辑方法,要调用多个方法来完成,所谓的方法内联就是把方法体内的代码直接植入到当前的方法体内,如下面代码:
public void m1(){
//.....
m2();
//...
}
private void m2(){
//do.....
}
当编译的时候 ,m2()字节数小到规定范围内时候,就会将m2()的方法体直接植入到m1()内,如下:
public void m1(){
//.....
//do.....
//...
}
可以在debug版本的JDK启动参数加上:-XX:+PrintLnLining来查看先关的内联信息。
②去虚拟化
主要是对类层次进行分析,当一个借口只有一个实现类的时候,那么在调用方法的时候,会将方法植入到方法体内,如:
piblic interface IParent(){
public void m();
}
public Child implements Iparent{
public void m(){
//do.....
}
}
public class Demo{
public void ip(Iparent child){
child.m();
}
}
由于只有Child实现IParent,最后编译的代码为:
public void ip(Iparent child){
//do....
}
③冗余消除
主要精简代码和消除无用的代码
如:
boolean status = false;
public void m(){
if(status){
//do....
}
//do..something.......
}
编译之后为:
public void m(){
//do...something....
}
2)server compiler(C2)
C2占用的内存比较多,但是用很多的优化技巧,它是基于逃逸分析进行优化的,所谓逃逸分析,就是一个方法内的一个变量 ,如果没有被外部引用过,那么就认为该变是逃逸的,否则是没有逃逸,基于逃逸分析的C2会做标量替换、栈上分配、同步消除等。
①标量替换
就是变量替换聚合量,如:
B b = new B("Tom mao");
System.out.println(b.name);
如果b在之后没有被用到过,那么标量替换后的代码为:
String name = "Tom mao";
System.out.println(name);
②栈上分配
就是把局部变量直接分配在栈上,当方法结束后 ,标量占用的内存也会随之而释放。
③同步消除
就是如果发现同步的对象 没有逃逸,那么就没有同步的必要,就会去掉同步的代码。
默认情况下 SUN JDK会根据机器的配置来选择相应的编辑为机器码方式,当机器配置cpu超过2核且内存超过2G会采用C2 ,但是在windows机器上始终会采用C1,可以启动时候加上-client或者-server来强制指定。