Java逃逸分析

Java逃逸分析


  1. java逃逸是什么东西?
  2. 我怎么知道是否开启了逃逸分析?
  3. 为什么对象可以不在堆上分配内存?
  4. 代码示例

1.java逃逸是什么东西?
可以理解为jvm为了减少GC和优化内存使用做出的一种优化方案,由JIT动态编译器进行优化,所以通过反编译是看不出来的

2.我怎么知道是否开启了逃逸分析?
逃逸分析的JVM参数是 DoEscapeAnalysis,通过java -client -XX:+PrintFlagsInitial 打印一下JVM参数默认值(我这里是1.8版本)

在这里插入图片描述
可以发现默认是开启了逃逸分析。

3.为什么对象可以不在堆上分配内存?
JVM逃逸做了如下几种对代码的优化,锁消除,标量替换等手段,将对象所需空间在栈中分配,减少gc回收,锁消除的JVM参数是EliminateLocks ,标量替换是EliminateAllocations,还是通过上面方法去搜索,发现默认是开启的(1.8版本)

在这里插入图片描述
在这里插入图片描述
4.代码示例
首先是锁消除,对象在方法内创建,并且在方法内加锁,这样是没有意义的,每一次调用方法都会new新的对象,并对新的对象加锁

private void sync() {
        Object o = new Object();
        synchronized(o) {
            System.out.println(o);
        }
    }

jit动态编译代码优化为

private  void sync(){
        Object o = new Object();
        System.out.println(o);
    }

在方法内部创建一个没有被外部引用的对象,就会不会发生逃逸,但是如果像下图这种,方法内部的对象被拿到外部使用了那么就发生了逃逸

private StringBuilder sync(String a,String b){
        StringBuilder sb = new StringBuilder();
        sb.append(a);
        sb.append(b);
        return sb;
    }

如果对象仅仅在方法内部使用,不将引用传递出去,是不会发生逃逸的,比如改成这样

private String sync(String a,String b){
        StringBuilder sb = new StringBuilder();
        sb.append(a);
        sb.append(b);
        return sb.toString();
    }

这样StringBuilder 的引用就消失了,会顺利的被回收掉,下面是标量替换,对象在方法内创建,无外部引用,会被标量所替换,减少GC和堆上内存使用

private void sync() {
   Sync sync= new Sync(1,2);
   System.out.println("x"+sync.x +"y" +sync.y);
}
class Sync{
        public Sync(int x, int y) {
            this.x = x;
            this.y = y;
        }
        private int x;
        private int y;

    }

替换结果

private void sync(){
        int x = 1;
        int y = 2;
        System.out.println("x"+sync.x +"y" +sync.y);
    }

参考博客

JIT百度百科

你可能感兴趣的:(JVM)