37.堆是分配对象存储的唯一选择吗?什么是逃逸分析?
1.堆是分配对象存储的唯一选择吗?
不是。如果经过逃逸分析(Escape Analysis)
后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。
2.逃逸分析
1.什么是逃逸分析?
分析一个对象的引用的使用范围从而决定是否要将这个对象分配到堆上。a)
当一个对象在方法中被定义后,对象如果只在方法内部使用,则认为没有发生逃逸;(没有发生逃逸的对象,会在栈上分配)b)
当一个对象在方法中被定义后,它被外部方法所引用,则认为发生了逃逸。
没有逃逸的例子:
例子1
:
对象v
没有在方法外部被引用。
例子2
:
如果直接return sb
的话,sb
指向的对象会在createStringBuffer
方法外部被使用,存在逃逸现象。会在堆上分配内存。
如果改成return sb.toString
,sb
对象就只在createStringBuffer
方法内部被使用,所以没有发生逃逸。会在栈上分配内存。
3.判断是否发生逃逸
如何快速的判断是否发生了逃逸分析?
看new
的对象实体是否有可能在方法外被调用。注意是看new
出来的实体,而不是那个引用变量。
例如,下面的例子中的第四种情况,虽然 EscapeAnalysis e
这个引用变量没有在方法外部被使用,但是它指向的new
出来的实体对象是可能被方法外部使用的,所以也存在逃逸。
public class EscapeAnalysis { public EscapeAnalysis obj; /* 方法返回EscapeAnalysis对象,发生逃逸 */ public EscapeAnalysis getInstance(){ return obj == null? new EscapeAnalysis() : obj; } /* 为成员属性赋值,发生逃逸 */ public void setObj(){ this.obj = new EscapeAnalysis(); } //思考:如果当前的obj引用声明为static的?仍然会发生逃逸。 /* 对象的作用域仅在当前方法中有效,没有发生逃逸 */ public void useEscapeAnalysis(){ EscapeAnalysis e = new EscapeAnalysis(); } /* 引用成员变量的值,发生逃逸。 */ public void useEscapeAnalysis1(){ EscapeAnalysis e = getInstance(); //getInstance().xxx()同样会发生逃逸 } }
逃逸分析参数设置:JDK7
及以后默认开启。