逃逸分析
在計(jì)算機(jī)語(yǔ)言編譯器語(yǔ)言優(yōu)化管理中颓哮,分析指針動(dòng)態(tài)范圍的方法稱(chēng)之為逃逸分析袭异。
通俗點(diǎn)講颈娜,當(dāng)一個(gè)對(duì)象的指針被多個(gè)方法或線程引用時(shí)自晰,我們稱(chēng)這個(gè)指針發(fā)生了逃逸凝化。
public class G {
public static B b;
public void globalVariablePointerEscape(){//給全局變量賦值稍坯,發(fā)生逃逸
b=new B();
}
public B methodPointerEscape(){//方法返回值酬荞,發(fā)生逃逸
return new B();
}
public void instancePassPointerEscape(){
methodPointerEscape().printClassName(this);//實(shí)例引用發(fā)生逃逸
}
}
class B{
public void printClassName(G g){
System.out.println(g.getClass().getName());
}
}
在這個(gè)例子中搓劫,一共舉了3種常見(jiàn)的指針逃逸場(chǎng)景。分別是 全局變量賦值混巧,方法返回值枪向,實(shí)例引用傳遞。
逃逸分析優(yōu)化JVM原理
我們知道java對(duì)象是在堆里分配的咧党,在調(diào)用棧中秘蛔,只保存了對(duì)象的指針。
當(dāng)對(duì)象不再使用后傍衡,需要依靠GC來(lái)遍歷引用樹(shù)并回收內(nèi)存深员,如果對(duì)象數(shù)量較多,將給GC帶來(lái)較大壓力蛙埂,也間接影響了應(yīng)用的性能倦畅。減少臨時(shí)對(duì)象在堆內(nèi)分配的數(shù)量,無(wú)疑是最有效的優(yōu)化方法绣的。
怎么減少臨時(shí)對(duì)象在堆內(nèi)的分配數(shù)量呢叠赐?不可能不實(shí)例化對(duì)象吧!
場(chǎng)景介紹
其實(shí)屡江,在java應(yīng)用里普遍存在一種場(chǎng)景芭概。一般是在方法體內(nèi),聲明了一個(gè)局部變量惩嘉,且該變量在方法執(zhí)行生命周期內(nèi)未發(fā)生逃逸(在方法體內(nèi)罢洲,未將引用暴露給外面)。
按照J(rèn)VM內(nèi)存分配機(jī)制文黎,首先會(huì)在堆里創(chuàng)建變量類(lèi)的實(shí)例奏路,然后將返回的對(duì)象指針壓入調(diào)用棧,繼續(xù)執(zhí)行臊诊。
這是優(yōu)化前鸽粉,JVM的處理方式。
逃逸分析優(yōu)化 - 棧上分配
優(yōu)化原理:分析找到未逃逸的變量抓艳,將變量類(lèi)的實(shí)例化內(nèi)存直接在棧里分配(無(wú)需進(jìn)入堆)触机,分配完成后,繼續(xù)在調(diào)用棧內(nèi)執(zhí)行玷或,最后線程結(jié)束儡首,棧空間被回收偏友,局部變量對(duì)象也被回收蔬胯。
這是優(yōu)化后的處理方式,對(duì)比可以看出位他,主要區(qū)別在椃毡簦空間直接作為臨時(shí)對(duì)象的存儲(chǔ)介質(zhì)产场。從而減少了臨時(shí)對(duì)象在堆內(nèi)的分配數(shù)量。
逃逸分析的原理很簡(jiǎn)單舞竿,但JVM在應(yīng)用過(guò)程中京景,還是有諸多考慮。
比如骗奖,逃逸分析不能在靜態(tài)編譯時(shí)進(jìn)行确徙,必須在JIT里完成。原因是执桌,與java的動(dòng)態(tài)性有沖突鄙皇。因?yàn)槟憧梢栽谶\(yùn)行時(shí),通過(guò)動(dòng)態(tài)代理改變一個(gè)類(lèi)的行為仰挣,此時(shí)育苟,逃逸分析是無(wú)法得知類(lèi)已經(jīng)變化了。
逃逸分析并不是直接的優(yōu)化手段椎木,而是一個(gè)代碼分析违柏,通過(guò)動(dòng)態(tài)分析對(duì)象的作用域,為其它優(yōu)化手段如棧上分配香椎、標(biāo)量替換和同步消除等提供依據(jù)漱竖,發(fā)生逃逸行為的情況有兩種:方法逃逸和線程逃逸。
1畜伐、方法逃逸:當(dāng)一個(gè)對(duì)象在方法中定義之后馍惹,作為參數(shù)傳遞到其它方法中;
2玛界、線程逃逸:如類(lèi)變量或?qū)嵗兞客蚍赡鼙黄渌€程訪問(wèn)到;
如果不存在逃逸行為慎框,則可以對(duì)該對(duì)象進(jìn)行如下優(yōu)化:同步消除良狈、標(biāo)量替換和棧上分配。
同步消除
線程同步本身比較耗笨枯,如果確定一個(gè)對(duì)象不會(huì)逃逸出線程薪丁,無(wú)法被其它線程訪問(wèn)到,那該對(duì)象的讀寫(xiě)就不會(huì)存在競(jìng)爭(zhēng)馅精,則可以消除對(duì)該對(duì)象的同步鎖严嗜,通過(guò)-XX:+EliminateLocks可以開(kāi)啟同步消除。
標(biāo)量替換
1洲敢、標(biāo)量是指不可分割的量漫玄,如java中基本數(shù)據(jù)類(lèi)型和reference類(lèi)型,相對(duì)的一個(gè)數(shù)據(jù)可以繼續(xù)分解压彭,稱(chēng)為聚合量睦优;
2渗常、如果把一個(gè)對(duì)象拆散,將其成員變量恢復(fù)到基本類(lèi)型來(lái)訪問(wèn)就叫做標(biāo)量替換刨秆;
3凳谦、如果逃逸分析發(fā)現(xiàn)一個(gè)對(duì)象不會(huì)被外部訪問(wèn)忆畅,并且該對(duì)象可以被拆散衡未,那么經(jīng)過(guò)優(yōu)化之后,并不直接生成該對(duì)象家凯,而是在棧上創(chuàng)建若干個(gè)成員變量缓醋;
通過(guò)-XX:+EliminateAllocations可以開(kāi)啟標(biāo)量替換, -XX:+PrintEliminateAllocations查看標(biāo)量替換情況绊诲。
棧上分配
故名思議就是在棧上分配對(duì)象送粱,其實(shí)目前Hotspot并沒(méi)有實(shí)現(xiàn)真正意義上的棧上分配,實(shí)際上是標(biāo)量替換掂之。
作者:占小狼
鏈接:http://www.reibang.com/p/20bd2e9b1f03
來(lái)源:簡(jiǎn)書(shū)
著作權(quán)歸作者所有抗俄。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)繫作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)?jiān)]明出處世舰。