深入理解java虚拟机-编译优化(9)

现在 java很少针对前端编译进行优化(java--->class文件的过程),主要都放到后端编译优化了。

java泛型

java泛型是JDK1.5之后新增的语法糖,在java编译成class文件的时候,会擦除相关的类型信息,

其中signature存储方法在字节码层面的特征签名,通过反射还是能获取相关的类型信息的,

 

对于编译后期优化,java程序刚开始是通过解释执行的,java虚拟机会探测出热点代码进行编译,编译成与本地平台

相关的机器码,这个就是 just in time compiler 即时编译器。

解释器一般情况下是和编译器一起工作的,因为解释器可以迅速启动和执行,当进行激进编译优化,出现问题后回退到解释模式

继续执行代码。

编译器还分为client模式和server模式,

client模式会进行简单的,可靠的优化,

server模式,可以编译出优化程度更高的的代码,当然耗时也会更高,会挤占用户运行代码的时间

热点代码(方法被调用多次,或者循环体)是怎么探测出来的呢?

Hotspot采用的是基于计数器的热点探测,即为每个代码块,维护计数器,调用一次就+1。

默认client模式下1500次,server模式下10000次,可以通过虚拟机参数 -XX:CompileThreshold来设定。

阈值有两个,一个是方法调用计数器,一个回边计数器,

 

方法调用计数器计数过程是,如果存在编译版本,使用编译版本执行代码,如果不存在 方法调用计数器加1然后判断

(回边+方法)值是否大于阈值,如果大于开始即时编译,这次的执行还是会使用解释执行。

同时还有一个 类似 TCP(出现丢失)传输的速度机制,当某个时间段内方法的调用次数不满足阈值的时候,这个时候

方法调用计数器就会减半,可以通过-XX:-UseCounterDeeay关闭这个限制,即采用准确的调用次数,

也可以使用-XX:CounterHalfLifeTime来设置这个周期的大小,单位秒

 

回边计数器,即统计循环体执行的次数,和上面基本一致,判断(方法+回边)是否大于回边阈值

 

编译优化,到底优化什么呢?

如方法内联,伪代码

 

冗余访问

公共子表达式消除,

 

 

逃逸分析

如果在方法体内,对象被外部引用,赋值给方法外部的变量,被传递出方法外,被其他线程访问到,这个就称为逃逸。

如果不会出现上述情况的话,那么久可以进行逃逸分析优化。

栈上分配对象,都认为对象是分配到堆中的,实际上对象有可能会分配到栈中,这样的好处就是不需要垃圾回收期回收,

只需要随着栈帧的出栈即可,完成对象的回收。

锁消除,如果一个变量没有逃逸,也不会被其他线程访问,针对这个变量的读写就不会有竞争问题,可消除锁

标量替换,把java一个对象拆散,根据程序访问,将原本的对象内出成员变量恢复到原始类型来访问。

-XX:-/+DoEscapeAnalysis

关闭或者开启逃逸分析,下面这段伪代码

class Student{

     String  name;

    Adress adress;

}

class Adress{

 String  name;

}

main{

    while(true){

     Adress address = new Adress();//如果开启逃逸分析,实际上会进行标量替换,不会创建对象,也就没Address对象

    Student Student = new Student();//即使开启逃逸分析,也会创建大量对象

   }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值