|
逃逸分析英文作Escape
Analysis。在計算機語言編譯器優(yōu)化原理中,逃逸分析是指分析指針動態(tài)范圍的方法,它同編譯器優(yōu)化原理的指針分析和外形分析相關(guān)聯(lián)。
當(dāng)變量(或者對象)在方法中分配后,其指針有可能被返回或者被全局引用,這樣就會被其他過程或者線程所引用,這種現(xiàn)象稱作指針(或者引用)的逃逸(Escape)。
在Java中比如下面的方法:
......
static V global_v;
public void a_method(){
V
v=b_method();
c_method();
}
public V b_method(){
V v=new
V();
return v;
}
public void c_method(){
global_v=new
V();
}
其中b_method方法內(nèi)部生成的V對象的引用被返回給a_method方法內(nèi)的變量v,c_method方法內(nèi)生成的V對象被賦給了全局變量global_v。這兩種場景都發(fā)生了指針(引用)逃逸。
逃逸分析研究對于Java編譯器有什么好處?我們知道Java對象總是在堆中分配的,因此Java對象的創(chuàng)建和回收對系統(tǒng)的開銷是很大的。Java語言被批評的一個地方,也是認為Java性能慢的一個原因就是Java不支持運行時棧分配對象,缺少像C#里面的值對象或者C++里面的struct結(jié)構(gòu)。
前面一篇文章《Java并發(fā)編程-常量對象(七)》就曾討論過這個問題,這是Swing內(nèi)存和性能消耗的瓶頸。近幾年業(yè)界曾進行過激烈討論,Java
6中是否應(yīng)該加入棧分配對象。其中有人主張可以通過JIT進行逃逸分析的方式來解決目前的問題,不用在語言級別進行支持,虛擬機支持棧分配機制,由JIT對代碼進行內(nèi)聯(lián)優(yōu)化和逃逸分析。
那么JIT怎么通過逃逸分析進行代碼優(yōu)化呢?分析下面的過程代碼:
public void my_method(){
V v=new
V();
//use
v
......
v=null;
}
在這個方法中創(chuàng)建的局部對象被賦給了v,但是沒有返回,沒有賦給全局變量等等操作,因此這個對象是沒有逃逸的,是可以在運行時棧進行分配和銷毀的對象。沒有發(fā)生逃逸的對象由于生命周期都在一個方法體內(nèi),因此它們是可以在運行時棧上分配并銷毀。
這樣在JIT編譯Java偽代碼時,如果能分析出這種代碼,那么非逃逸對象其創(chuàng)建和回收就可以在棧上進行,從而能大大提高Java的運行性能。
另外為什么要在逃逸分析之前進行內(nèi)聯(lián)分析呢?這是因為往往有些對象在被調(diào)用過程中創(chuàng)建并返回給調(diào)用過程,調(diào)用過程使用完該對象就銷毀了。這種情況下如果將這些方法進行內(nèi)聯(lián),它們就由兩個方法體變成一個方法體了,這種原來通過返回傳遞的對象就變成了方法內(nèi)的局部對象,就變成了非逃逸對象了,這樣這些對象就可以在同一棧上進行分配了。
據(jù)說Java
6的虛擬機已經(jīng)支持對象的棧分配和逃逸分析機制了,但目前并沒有啟動。具可靠的消息,Java
7中將啟動這一功能。這對Swing來說又是一次大規(guī)模提升速度的機會。
除能將堆分配對象變成棧分配對象,逃逸分析還有其他兩個優(yōu)化應(yīng)用。一是同步消除。我們知道線程同步的代價是相當(dāng)高的,同步的后果是降低并發(fā)性和性能。逃逸分析可以判斷出某個對象是否始終只被一個線程訪問,如果只被一個線程訪問,那么對該對象的同步操作就可以轉(zhuǎn)化成沒有同步保護的操作,這樣就能大大提高并發(fā)程度和性能。
二是矢量替代。逃逸分析方法如果發(fā)現(xiàn)對象的內(nèi)存存儲結(jié)構(gòu)不需要連續(xù)進行的話,就可以將對象的部分甚至全部都保存在CPU寄存器內(nèi),這樣能大大提高訪問速度。
Java
7將完全支持了棧式分配對象,JIT將支持逃逸分析優(yōu)化,另外Java
7還將缺省支持OpenGL的加速功能,光這三種平臺性能的提升就會給Swing帶來又一次性能的革命。
Swing的未來越來越光明
|