编译器中的 逃逸分析

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

逃逸分析

在计算机语言编译器语言优化管理中,分析指针动态范围的方法称之为逃逸分析。

通俗点讲,当一个对象的指针被多个方法或线程引用时,我们称这个指针发生了逃逸。

public class G {
    public static B b;
    
    public void globalVariablePointerEscape(){//给全局变量赋值,发生逃逸
        b=new B();
    }
    
    public B methodPointerEscape(){//方法返回值,发生逃逸
        return new B();
    }
    
    public void instancePassPointerEscape(){
        methodPointerEscape().printClassName(this);//实例引用发生逃逸
    }
    
    
}

class B{
    public void printClassName(G g){
        System.out.println(g.getClass().getName());
    }
}

在这个例子中,一共举了3种常见的指针逃逸场景。分别是 全局变量赋值,方法返回值,实例引用传递。

逃逸分析优化JVM原理

我们知道java对象是在堆里分配的,在调用栈中,只保存了对象的指针。

当对象不再使用后,需要依靠GC来遍历引用树并回收内存,如果对象数量较多,将给GC带来较大压力,也间接影响了应用的性能。减少临时对象在堆内分配的数量,无疑是最有效的优化方法。

怎么减少临时对象在堆内的分配数量呢?不可能不实例化对象吧!

场景介绍

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

这是优化前,JVM的处理方式。

逃逸分析优化 - 栈上分配

优化原理:分析找到未逃逸的变量,将变量类的实例化内存直接在栈里分配(无需进入堆),分配完成后,继续在调用栈内执行,最后线程结束,栈空间被回收,局部变量对象也被回收。

这是优化后的处理方式,对比可以看出,主要区别在栈空间直接作为临时对象的存储介质。从而减少了临时对象在堆内的分配数量。

逃逸分析的原理很简单,但JVM在应用过程中,还是有诸多考虑。

比如,逃逸分析不能在静态编译时进行,必须在JIT里完成。原因是,与java的动态性有冲突。因为你可以在运行时,通过动态代理改变一个类的行为,此时,逃逸分析是无法得知类已经变化了。

逃逸分析并不是直接的优化手段,而是一个代码分析,通过动态分析对象的作用域,为其它优化手段如栈上分配、标量替换和同步消除等提供依据,发生逃逸行为的情况有两种:方法逃逸和线程逃逸。

1、方法逃逸:当一个对象在方法中定义之后,作为参数传递到其它方法中;
2、线程逃逸:如类变量或实例变量,可能被其它线程访问到;

如果不存在逃逸行为,则可以对该对象进行如下优化:同步消除、标量替换和栈上分配。

同步消除

线程同步本身比较耗,如果确定一个对象不会逃逸出线程,无法被其它线程访问到,那该对象的读写就不会存在竞争,则可以消除对该对象的同步锁,通过-XX:+EliminateLocks可以开启同步消除。

标量替换

1、标量是指不可分割的量,如java中基本数据类型和reference类型,相对的一个数据可以继续分解,称为聚合量;
2、如果把一个对象拆散,将其成员变量恢复到基本类型来访问就叫做标量替换;
3、如果逃逸分析发现一个对象不会被外部访问,并且该对象可以被拆散,那么经过优化之后,并不直接生成该对象,而是在栈上创建若干个成员变量;
通过-XX:+EliminateAllocations可以开启标量替换, -XX:+PrintEliminateAllocations查看标量替换情况。

栈上分配

故名思议就是在栈上分配对象,其实目前Hotspot并没有实现真正意义上的栈上分配,实际上是标量替换。

作者:占小狼
鏈接:http://www.jianshu.com/p/20bd2e9b1f03
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

相关文章
【逃逸分析】
【逃逸分析】
|
6月前
|
存储 算法 编译器
C/C++编译器局部优化技术:局部优化是针对单个函数或基本块进行的优化
C/C++编译器局部优化技术:局部优化是针对单个函数或基本块进行的优化
170 0
|
5月前
|
存储 Java 编译器
HotSpot逃逸分析
HotSpot逃逸分析
37 1
|
6月前
|
存储 缓存 Java
深入理解Java中的逃逸分析
深入理解Java中的逃逸分析
107 0
|
监控 编译器
volatile的扩展分析(1)———分析JIT编译器优化
volatile的扩展分析(1)———分析JIT编译器优化
91 1
|
6月前
|
设计模式 消息中间件 Java
面试官:什么是JIT、逃逸分析、锁消除、栈上分配和标量替换?
面试官:什么是JIT、逃逸分析、锁消除、栈上分配和标量替换?
652 1
|
6月前
|
存储 Java
探究跨代引用和逃逸分析如何提升程序性能!
探究跨代引用和逃逸分析如何提升程序性能!
探究跨代引用和逃逸分析如何提升程序性能!
|
缓存 搜索推荐 Java
JVM 中的编译器
JVM 中的编译器
|
Java 编译器
JVM(三)逃逸分析
JVM(三)逃逸分析
59 0
|
安全 Java
【Java基础】This逃逸(This引用逃逸详解)
【Java基础】This逃逸(This引用逃逸详解)
167 0