一,是什么是逃逸分析?
逃逸分析是分析指针可以存储的所有地方,用于判断指针是否能确保在当前线程。
我理解的就是用来分析,一个对象是否仅在某个线程被访问到。
二,为什么要进行逃逸分析?
在JIT时,进行逃逸分析后,就可以确定对象仅在某一线程中被访问到,这样JIT就可以对其方法进行优化。
包括:
1.堆分配转化为栈分配
2.锁消除
3.分离对象或标量替换
具体方式见下文。
三,判断逃逸的标准有哪些?
1.对象被赋值给堆中的变量或者类的静态变量
2.对象被传进了不确定的代码中运行
下面举几个例子
public class EscapeTest {
public static Object globalVariableObject;
public Object instanceObject;
public void globalVariableEscape(){
globalVariableObject = new Object(); //静态变量,外部线程可见,发生逃逸
}
public void instanceObjectEscape(){
instanceObject = new Object(); //赋值给堆中实例字段,外部线程可见,发生逃逸
}
public Object returnObjectEscape(){
return new Object(); //返回实例,外部线程可见,发生逃逸
}
public void noEscape(){
synchronized (new Object()){
//仅创建线程可见,对象无逃逸
}
Object noEscape = new Object(); //仅创建线程可见,对象无逃逸
}
}
四,基于逃逸分析的优化
1.堆分配转化为栈分配
如果一个对象的指针不会发生逃逸,那么就可以把该对象分配在栈上,这样在栈帧弹出时回收该对象,不用等到gc时,从而降低gc压力和频率。
2.锁消除
如果一个对象不会发生逃逸,只被一个线程访问,那么在这个对象上的操作就不需要进行同步
3.分离对象或标量替换
如果一个对象不会发生逃逸,可以将该对象分解成一个个基本变量,分配栈上。这样有两点好处,1.不用再生成对象头,从而减少开销。2.空间回收更为高效,同其他栈分配资源。
五,逃逸分析优化案例
1.堆分配转化为栈分配
虚拟机配置参数:-XX:+PrintGC -Xms20M -Xmn20M -XX:+DoEscapeAnalysis
-XX:+DoEscapeAnalysis表示开启逃逸分析,JDK8是默认开启的
-XX:+PrintGC 表示打印GC信息
-Xms20M -Xmn20M 设置JVM内存大小是20M
public static void main(String[] args){
for(int i = 0; i < 5_000_000; i++){
createObject();
}
}
public static void createObject(){
new Object();
}
运行结果,没有进行频繁的gc
将逃逸分析关闭 -XX:-DoEscapeAnalysis
再次运行
发生频繁的gc
2.锁消除
虚拟机配置参数:-XX:+PrintGC -Xms500M -Xmn500M -XX:+DoEscapeAnalysis。配置500M是保证不触发GC。
开启逃逸分析时,用了4毫秒。
注意这个耗时,跟不加锁的上面测试是一致的。
现在关闭逃逸分析再测
用了111ms。
以上