逃逸分析
逃逸分析(Escape Analysis
)的基本原理是:分析对象动态作用域,当一个对象在方法里面
被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,这种称为方法逃逸。
甚至可能被外部线程访问到,譬如赋值给可以在其他线程中访问的实例变量,这种称为线程逃逸。
利用逃离分析进行优化
栈上分配(Stack Allocations)
如果确定一个对象不会逃逸到线程之外,那可以让这个对象在栈上分配内存,对象占用的内存空间
就可以随栈桢出栈而销毁。栈上分配可以支持方法逃逸,但不能支持线程逃逸。
标量替换(Scalar Replacement)
若一个数据已经无法再分解成更小的数据来表示(如Java
的基本类型,reference类型等),那么这些数据就可以被
称为标量。相对的,如果一个数据可以继续分解,那它就被称为聚变量(Aggregate
,如Java
对象)。
把一个Java
对象拆散,根据程序访问的情况,将其用到的成员变量恢复为原始类型来访问,
这个过程就被称为标量替换。加入逃逸分析能够证明一个对象不会被方法外部访问,并且这个对象可以被拆散,
那么程序真正执行的时候将可能不去创建这个对象,而改为直接创建它的若干个被这个方法使用的成员变量来替代。
将对象拆分后除了可以让对象的成员变量在栈上,还可以为后续进一步优化手段创建条件。
标量替换可以视作栈上分配的一种特例,但对逃逸程度要求更高,不允许对象逃逸出方法范围内。
同步消除(Synchronization Elimination)
线程同步本身是一个相对耗时的过程,如果逃逸分析能够确定一个变量不会逃逸出线程,无法被
其他线程访问,那么这个变量的读写肯定就不会有竞争,对这个变量的同步措施也就可以安全地
消除掉。
使用情况
JDK7
逃逸分析才称为服务端编译器默认开启的选项。可以使用-XX:+DoEscapeAnalysis
手动开启
逃逸分析,开启之后可以通过参数-XX:PrintEscapeAnalysis
查看分析结果。开启逃逸分析之后,
可以使用-XX:+EliminateAllocations
开启标量替换,使用-XX:EliminateLocks
开启同步消除,
使用-XX:PrintEliminateAllcations
查看标量替换情况。