美文网首页
逃逸分析

逃逸分析

作者: 大海孤了岛 | 来源:发表于2017-09-03 12:21 被阅读129次

逃逸分析

在编程语言的编译优化原理中,分析指针动态范围的方法称之为逃逸分析。通俗来讲,当一个对象的指针被多个方法或线程引用时,我们称这个指针发生了逃逸。

常见的逃逸场景:全局变量赋值、方法返回值、实例引用传递

public class A {

    public static B b;
    
    //给全局变量赋值,发生逃逸
    public void globalVariablePointerEscape(){
        b = new B();
    }

    //方法返回值,发生逃逸
    public B methodPointerEscape(){
        return new B();
    }

    //实例引用传递,发生逃逸
    public void instancePassPointerEscape(){
        methodPointerEscape().printClassName(this);
    }

}

public class B {

    public void printClassName(A a){
        System.out.println(a.getClass().getName());
    }

}

逃逸分析原理

我们知道Java对象是在堆里分配的,在调用栈中,只保存了对象的指针。当对象不再使用后,需要依靠GC来遍历引用树并回收内存,如果对象数量较多,将给GC带来较大压力。因此,减少临时对象在堆内存分配的数量是最有效的优化方法。

场景应用一:栈上分配

其实,在java应用里普遍存在一种场景。一般是在方法体内,声明了一个局部变量,且该变量在方法执行生命周期内未发生逃逸(在方法体内,未将引用暴露给外面)。按照JVM内存分配机制,首先会在堆里创建变量类的实例,然后将返回的对象指针压入调用栈,继续执行。这是优化前,JVM的处理方式。

  • 逃逸分析优化 - 栈上分配

分析找到未逃逸的变量,将变量类的实例化内存直接在栈里分配(无需进入堆),分配完成后,继续在调用栈内执行,最后线程结束,栈空间被回收,局部变量对象也被回收。对比可以看出,主要区别在栈空间直接作为临时对象的存储介质。从而减少了临时对象在堆内的分配数量。

应用场景二:同步消除

在即使编译器时,如果发现不可能被共享的对象,则可以消除这些对象的锁操作。

也许你会觉得奇怪,既然有些对象不可能被多线程访问,那为什么要加锁呢?写代码时直接不加锁不就好了。但是有时,这些锁并不是程序员所写的,有的是JDK实现中就有锁的,比如Vector和StringBuffer这样的类,它们中的很多方法都是有锁的。当我们在一些不会有线程安全的情况下使用这些类的方法时,达到某些条件时,编译器会将锁消除来提高性能。

public class BufferTest {

    public static void main(String[] args){
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i ++){
            createStringBuffer("JVM", "EscapeAnalysis");
        }
        long end = System.currentTimeMillis();
        System.out.println("it takes " + (end - start) + " ms");

    }

    public static String createStringBuffer(String s1, String s2){
        StringBuffer sb = new StringBuffer();
        sb.append(s1);
        sb.append(s2);
        return sb.toString();
    }

}

优化前:
it takes 867 ms
优化后:
it takes 802 ms

基于逃逸分析,JVM可以判断,如果这个局部变量StringBuffer并没有逃出它的作用域,那么可以确定这个StringBuffer并不会被多线程所访问,那么就可以把这些多余的锁给去掉来提高性能。

应用场景三:标量替换

Java虚拟机中的原始数据类型(int,long等数值类型以及reference类型等)都不能再进一步分解,它们就可以称为标量。相对的,如果一个数据可以继续分解,那它称为聚合量,Java中最典型的聚合量是对象。如果逃逸分析证明一个对象不会被外部访问,并且这个对象是可分解的,那程序真正执行的时候将可能不创建这个对象,而改为直接创建它的若干个被这个方法使用到的成员变量来代替。拆散后的变量便可以被单独分析与优化,可以各自分别在栈帧或寄存器上分配空间,原本的对象就无需整体分配空间了。

相关文章

  • Java 逃逸分析

    > 什么是逃逸分析? - 关于 Java 逃逸分析的定义: - 逃逸分析(Escape Analysis)简单...

  • go 逃逸分析

    go 逃逸分析 什么是逃逸分析 逃逸分析决定一个变量是分配在堆上还是分配在栈上 原理 逃逸分析这种“骚操作”把变量...

  • (十三)golang 逃逸分析

    Golang逃逸分析 介绍逃逸分析的概念,go怎么开启逃逸分析的log。以下资料来自互联网,有错误之处,请一定告之...

  • 深入分析JVM逃逸分析对性能的影响

    逃逸分析(Escape Analysis) 逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,...

  • JVM内存逃逸

    逃逸分析(Escape Analysis)是目前Java虚拟机中比较前沿的优化技术。 逃逸分析的基本行为就是分析对...

  • jvm 优化篇-(4)-栈上分配与逃逸分析 -XX:+DoEsc

    逃逸分析(Escape Analysis) 逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,...

  • 逃逸分析

    逃逸分析 在编程语言的编译优化原理中,分析指针动态范围的方法称之为逃逸分析。通俗来讲,当一个对象的指针被多个方法或...

  • 逃逸分析

    做个笔记,参开其他资料学习一下,以下纯属个人见解,如有错误之处,欢迎讨论和纠正。 参考资料 JVM的逃逸分析深入分...

  • 逃逸分析

    逃逸分析(Escape Analysis)是目前Java虚拟机中比较前沿的优化技术,他与类型继承关系分析一样,并不...

  • 逃逸分析

    https://zh.wikipedia.org/wiki/%E9%80%83%E9%80%B8%E5%88%86...

网友评论

      本文标题:逃逸分析

      本文链接:https://www.haomeiwen.com/subject/hnwdjxtx.html