逃逸分析( Escape Analysis) 是目前Java虛擬機(jī)中比較前沿的優(yōu)化技術(shù), 它與類型繼承關(guān)系分析一樣酵颁, 并不是直接優(yōu)化代碼的手段, 而是為其他優(yōu)化手段提供依據(jù)的分析技術(shù)。
逃逸分析的基本行為就是分析對象動態(tài)作用域: 當(dāng)一個對象在方法中被定義后, 它可能被外部方法所引用哑梳, 例如作為調(diào)用參數(shù)傳遞到其他方法中, 稱為方法逃逸绘盟。 甚至還有可能被外部線程訪問到鸠真, 譬如賦值給類變量或可以在其他線程中訪問的實(shí)例變量, 稱為線程逃逸龄毡。
如果能證明一個對象不會逃逸到方法或線程之外吠卷, 也就是別的方法或線程無法通過任何途徑訪問到這個對象, 則可能為這個變量進(jìn)行一些高效的優(yōu)化沦零,如下所示:
棧上分配( Stack Allocation):
Java虛擬機(jī)中祭隔, 在Java堆上分配創(chuàng)建對象的內(nèi)存空間幾乎是Java程序員都清楚的常識了, Java堆中的對象對于各個線程都是共享和可見的路操, 只要持有這個對象的引用疾渴, 就可以訪問堆中存儲的對象數(shù)據(jù)。 虛擬機(jī)的垃圾收集系統(tǒng)可以回收堆中不再使用的對象屯仗, 但回收動作無論是篩選可回收對象程奠, 還是回收和整理內(nèi)存都需要耗費(fèi)時間。如果確定一個對象不會逃逸出方法之外祭钉, 那讓這個對象在棧上分配內(nèi)存將會是一個很不錯的主意瞄沙, 對象所占用的內(nèi)存空間就可以隨棧幀出棧而銷毀。 在一般應(yīng)用中慌核, 不會逃逸的局部對象所占的比例很大距境, 如果能使用棧上分配, 那大量的對象就會隨著方法的結(jié)束而自動銷毀了垮卓, 垃圾收集系統(tǒng)的壓力將會小很多垫桂。同步消除( Synchronization Elimination):
線程同步本身是一個相對耗時的過程, 如果逃逸分析能夠確定一個變量不會逃逸出線程粟按, 無法被其他線程訪問诬滩, 那這個變量的讀寫肯定就不會有競爭, 對這個變量實(shí)施的同步措施也就可以消除掉灭将。標(biāo)量替換( Scalar Replacement) :
標(biāo)量( Scalar) 是指一個數(shù)據(jù)已經(jīng)無法再分解成更小的數(shù)據(jù)來表示了疼鸟, Java虛擬機(jī)中的原始數(shù)據(jù)類型( int、 long等數(shù)值類型以及reference類型等)都不能再進(jìn)一步分解庙曙, 它們就可以稱為標(biāo)量空镜。 相對的, 如果一個數(shù)據(jù)可以繼續(xù)分解, 那它就稱作聚合量( Aggregate)吴攒,Java中的對象就是最典型的聚合量张抄。 如果把一個Java對象拆散,根據(jù)程序訪問的情況洼怔, 將其使用到的成員變量恢復(fù)原始類型來訪問就叫做標(biāo)量替換署惯。如果逃逸分析證明一個對象不會被外部訪問, 并且這個對象可以被拆散的話镣隶, 那程序真正執(zhí)行的時候?qū)⒖赡懿粍?chuàng)建這個對象极谊,而改為直接創(chuàng)建它的若干個被這個方法使用到的成員變量來代替。將對象拆分后矾缓,除了可以讓對象的成員變量在棧上( 棧上存儲的數(shù)據(jù), 有很大的概率會被虛擬機(jī)分配至物理機(jī)器的高速寄存器中存儲) 分配和讀寫之外稻爬, 還可以為后續(xù)進(jìn)一步的優(yōu)化手段創(chuàng)建條件嗜闻。