java逃逸分析

循环一:

  Object o;
        for (int i = 0; i < 100; i++) {
            o = new Object();
            System.out.println(o.hashCode());
        }

循环二:

  for (int i = 0; i < 100; i++) {
            Object o = new Object();
            System.out.println(o.hashCode());
        }

以前看很多博客,大多数都主张循环一的写法,依据是可以减少栈上变量的分配。
但是今天看了JVM的逃逸分析后,个人觉得循环二的写法要好点,因为变量没有逃逸出循环体外,在经过JIT编译优化后,Object对象可以被分配在栈上。这样就减少了GC次数,也减小了堆内存的使用压力。
看文档说jdk7后默认开启了逃逸分析,现在用的jdk8。
求问下大佬这样理解有没有错误?还有就是到底那个写法好点?

阅读 1.7k
3 个回答

两种写法编译得到的字节码是一样的,不需要jit优化,编译器就已经处理好了,所以第二种可读性更好也更优
这里要更正的是,至少截止到目前的版本(Valhalla正式发布之前),只要是对象,都在堆上,不存在“对象被分配在栈上”

逃逸分析一般是基于方法的,栈分配可能还没那么容易,不过标量替换也能提升一定的效率。

新手上路,请多包涵

逃逸分析的基本行为就是分析对象动态作用域: 当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有发生逃逸。JIT 编译器在编译期间根据逃逸分析的结果,发现如果一个对象并没有逃逸出方法的话,就可能被优化成栈上分配。在 JIT 阶段,通过逃逸分析确定该对象不会被外部访问,并且对象可以被进一步分解时,JVM 不会创建该对象,而会将该对象成员变量分解若干个被这个方法使用的成员变量所代替。这些代替的成员变量在栈帧或寄存器上分配空间,这个过程就是标量替换。所以栈上分配其实严格来说栈里存的不是对象,而是拆分后的基础类型变量。示例代码编译后的字节码是一样的。除非对象特别大,会导致栈内存溢出,没逃逸的对象肯定分配在栈上好啊,不然别人搞逃逸分析干什么,不就是为了栈帧弹出的时候一并回收资源,减少GC的操作

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏