逃逸分析:
是一种确定指针动态范围的静态分析,它可以分析在程序的哪些地方可以访问到指针。
原理:
逃逸分析的基本原理是 : 分析对象动态作用域,当一个对象在方法里面被定义后,他可能被外部方法所引用:
public class method_escape {
public Object getobject(){
Object o = new Object();
return o;
}
}
如上,这个对象可能作为返回参数传递到其他方法中,这种就称为 方法逃逸
。
也有可能被外部线程访问到:
public class Thread_escape {
Object object;
public void test(){
Object o = new Object();
object=o;
}
}
如上,赋值给了可以在其他线程中访问的实例变量,称为 线程逃逸
对象的逃逸程度 从低到高是 不逃逸
、方法逃逸
、线程逃逸
那么根据对象的逃逸程度,就会对对象实例采取不同的优化。此时就有可能出现对象不在堆中产生的情况了
栈上分配
如果确定一个对象不会逃逸出线程之外,那么让这个对象在栈上分配内存将会是一个很不错的主意,对象所占用的内存空间就可以随栈帧出栈而销毁。在一般应用中,完全不会逃逸的局部对象和不会逃逸出线程的对象所占的比例是很大的,如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁了。
标量替换
Java中的基本数据类型和reference类型都称为标量。像对象这种就称之为聚合量。
假如一逃逸分析能够证明一个对象不会被方法外部访问,并且这个对象可以拆散成标量,那么程序真正执行 的时候将可能不会去创建这个对象,而改为直接创建它的若干个被这个方法使用的成员变量来代替。
如下代码:
public class scalaReplace {
public int test(){
Point point = new Point(10, 5);
return point.getSum();
}
}
class Point{
int x;
int y;
public int getSum(){
return x+y;
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
根据标量替换,这个Point对象可能最终没有创建,而变成了如下代码:
public int test(){
int x=10;
int y=5;
return x+y;
}
同步消除
如果JVM通过逃逸分析,发现一个对象只能从一个线程被访问到,则访问这个对象时,可以不加同步锁。如果程序中使用了synchronized锁,则JVM会将synchronized锁消除。