如何快速判断是否逃逸就看方法内new的对象实体是否能够被外部方法进行调用
什么是逃逸分析
在java虚拟机中,对象是在java堆中分配内存的,这是一个普遍的常识。但是,有一种特殊情况,那就是如果经过逃逸分析(escape analysis)后发现,一个对象并没有,逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需在堆上分配内存,也无须进行垃圾回收了。这也是最常见的堆外存储技术。
这段蓝色的代码中将创建的 sb 引用作为返回值返回,那么其它线程就有可能拿到这个变量,因为堆是所有线程共享的这就叫发生了逃逸。而下面黄色的代码调用了toString方法底层会重新new一个StringBuffer()出来,这段代码中的sb会在方法结束时就被销毁,因此没有发生逃逸。
逃逸分析代码优化
方法内联
public class test{public static void main(string [] args){int res = add(1,2);}public int add (int x,int y){return x+y;}
}public class test{public static void main(string [] args){//方法内联,直接使用 add方法内部的逻辑int res = 1 + 2;}}
关于逃逸分析的论文在1999年就已经发表了,但直到jdr1.6才有实现,而且这项技术到如今也并不是十分成熟的。其根本原因就是无法保证逃逸分析的性能消耗一定能高于他的消耗。虽然经过逃逸分析可以做标量替换,栈上分配,和锁消除。但是逃逸分析自身也是需要进行一系列复杂的分析的,这其实也是一个相对耗时的过程。一个极端的例子,就是经过逃逸分析之后,发现没有一个对象是不逃逸的。那这个逃逸分析的过程就白白浪费掉了。虽然这项技术并不十分成熟,但是它也是即时编译器优化技术中一个十分重要的手段。注意到有一些观点,认为通过逃逸分析,jvm会在栈上分配那些不会逃逸的对象,这在理论上是可行的,但是取决于jvm设计者的选择。据我所知,oracle hotspot jvm中并未这么做,这一点在逃逸分析相关的文档里已经说明,所以可以明确所有的
对象实例都是创建在堆上。目前很多书籍还是基于jdk 7以前的版本,jdk已经发生了很大变化,intern字符串的缓存和静态变量曾经都被分配在永久代上,而永久代已经被元数据区取代。但是,
intern字符串缓存和静态变量并不是被转移到元数据区,而是直接在堆上分配,所以这一点同样符合前面一点的结论:对象实例都是分配在堆上。