简述 Java 的逃逸分析机制

2021.03.13 10:03 512
阅读约 4 分钟

逃逸分析

什么是逃逸

方法逃逸:当一个对象在方法里面被定义之后,他可能会被外部方法所引用,例如作为参数传递到其他方法,也及对象逃离了方法的作用范围,这种行为被称为方法逃逸。

线程逃逸:当被定义的对象赋值给可以被其他线程所访问的对象时,被称为线程逃逸。

从不逃逸到方法逃逸直至线程逃逸的过程,称为对象由低到高的不同逃逸程度。

那么为什么需要进行逃逸分析呢,当一个对象分析之后确定不会出现逃离作用范围的问题,那么可以通过一些手段来优化这些对象而减少资源的消耗,例如:

栈上分配[1]

众所周知,Java在堆中分配创建对象的内存空间。Java堆中的对象是线程共享的,也就是说,只要持有某个对象的引用,就可以访问到堆中的对象。虚拟机的垃圾回收器会回收不再使用的对象,但无论是筛选出不再使用的对象还是回收和整理内存,都是非常耗费资源的。如果确定一个对象不会存在线程逃逸的问题,例如局部对象等所占的比例是非常大的,如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁了,垃圾回收的压力也将大大减轻。

然而,这项优化仍在进行中。  

标量替换

若一个数据已经无法再分解成更小的数据来表示,例如Java虚拟机中的原始数据类型都不能再进一步分解了,那么这些数据就可以称为标量。如果一个数据类型可以被进一步分解,例如对象,那它就被称为聚合量

如果把一个对象拆散,根据程序访问的情况,将其用到的成员变量恢复到原始类型来访问,这个过程称为标量替换。

假如逃逸分析证明一个对象确实不会逃离方法的作用范围,并且这个对象可以被进一步分解,那么该对象可能在程序执行时不会被创建,而创建若干个被该方法使用的成员变量来代替。

同步消除

线程同步本身是一个相对耗时的过程,如果对一个变量进行逃逸分析确定不会逃出方法的作用范围,那么该变量一定不会出现线程安全问题,那么也就不需要对这个变量实施同步措施。

最后

逃逸分析这项技术至今尚未成熟,不成熟的原因主要是由于其计算成本太高,试想如果花费了大力气去寻找逃逸对象,而分析完毕后几乎找不到几个不逃逸的对象,那么这些运行期间耗费的资源就白白浪费了,因此虚拟机现在采用的的逃逸分析算法不那么准确,但时间压力相对较小。

 

[1]:由于复杂度等原因,HotSpot中目前暂时还没有做这项优化,但一些其他的虚拟机(如Excelsior
JET)使用了这项优化。

字数:965 发布于 6 个月前
Copyright 2018-2021 Siques