JVM優(yōu)化之逃逸分析與分配消除

要了解逃逸分析背后的基本原理,我們先來看下這段有問題的C代碼——當(dāng)然這個(gè)是沒法用Java來寫的:

左權(quán)網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),左權(quán)網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為左權(quán)上千多家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站建設(shè)要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的左權(quán)做網(wǎng)站的公司定做!

JVM優(yōu)化之逃逸分析與分配消除

這段C代碼在棧上創(chuàng)建了一個(gè)int類型的變量,然后把它的指針作為函數(shù)的返回值返回了。這樣做是有問題的,因?yàn)楫?dāng)gettheint()函數(shù)返回的時(shí)候,int所在的棧幀就已經(jīng)被銷毀了,后面你再去訪問這個(gè)地址的話,就不知道里面存儲(chǔ)的到底是什么了。

Java平臺(tái)設(shè)計(jì)的一個(gè)主要目標(biāo)就是要消除這種類型的bug。從設(shè)計(jì)上,JVM就不具備這種低級(jí)的“根據(jù)位置索引來讀內(nèi)存”的能力。這類操作對(duì)應(yīng)的Java字節(jié)碼是putfield和getfield。

來看下這段Java代碼:

JVM優(yōu)化之逃逸分析與分配消除

這段代碼創(chuàng)建了一億對(duì)隨機(jī)大小的矩形,并去計(jì)算有多少對(duì)是大小一樣的。每次迭代都會(huì)創(chuàng)建一對(duì)新的矩形。你可能會(huì)認(rèn)為main方法里會(huì)創(chuàng)建2億個(gè)Rect對(duì)象:一億個(gè)r1,一億個(gè)r2。

不過,如果某個(gè)對(duì)象只是在方法內(nèi)部創(chuàng)建并使用的話——也就是說,它不會(huì)傳遞到另一個(gè)方法中或者作為返回值返回——那么運(yùn)行時(shí)程序就還能做得更聰明一些。你可以說這個(gè)對(duì)象是沒有逃逸出去的,因此運(yùn)行時(shí)(其實(shí)就是JIT編譯器)做的這個(gè)分析又叫做逃逸分析。

如果一個(gè)對(duì)象沒有逃逸出去,那也就是說JVM可以針對(duì)這個(gè)對(duì)象做一些類似“棧自動(dòng)分配”的事情。在這個(gè)例子當(dāng)中,這個(gè)對(duì)象不會(huì)從堆上分配空間,因此它也不需要垃圾回收器來回收。一旦使用這個(gè)“棧分配(stack-allocated)”對(duì)象的方法返回了,這個(gè)對(duì)象所占用的內(nèi)存也就自動(dòng)被釋放掉了。

事實(shí)上,HotSpot VM的C2編譯器做的事情要比棧分配要復(fù)雜得多。我們現(xiàn)在就來看一下。

在HotSpot VM的源碼中,可以看到逃逸分析系統(tǒng)是如何對(duì)對(duì)象的使用進(jìn)行分類的:

JVM優(yōu)化之逃逸分析與分配消除

第一類說明這個(gè)對(duì)象可以用標(biāo)量來代替。這種分配消除技術(shù)叫標(biāo)量替換(scalar replacement)。這意味著這個(gè)對(duì)象會(huì)被拆解成它的構(gòu)成字段,這就相當(dāng)于分配對(duì)象的操作變成了在方法內(nèi)部創(chuàng)建多個(gè)局部變量。完成這個(gè)之后,另一項(xiàng)HotSpot VM的JIT技術(shù)會(huì)參與進(jìn)來,它會(huì)將這些字段(事實(shí)上已經(jīng)是局部變量了)存儲(chǔ)到CPU的寄存器中(如果有必要就存儲(chǔ)在棧上)。

Java平臺(tái)的主要挑戰(zhàn)是執(zhí)行模型非常復(fù)雜。在上述例子中,如果只看源代碼,你會(huì)認(rèn)為r1對(duì)象是不會(huì)逃逸出main方法外的,但r2會(huì)作為參數(shù)傳給r1的sameArea方法,因此它逃逸出了main方法外。

根據(jù)上面的分類,乍一看的話r1應(yīng)該歸類為NoEscape,而r2應(yīng)該歸為ArgEscape;不過這個(gè)結(jié)論是錯(cuò)誤的,原因有幾點(diǎn)。

第一,回想一下,Java中的方法調(diào)用最終會(huì)通過編譯器替換為字節(jié)碼invoke。它會(huì)把調(diào)用目標(biāo)(也就是接收對(duì)象,注:即要調(diào)用的對(duì)象)和入?yún)⑻畛涞綏V?,然后查找到這個(gè)方法,再分發(fā)給它(也就是執(zhí)行這個(gè)方法)。

這意味著接收對(duì)象也被傳入了調(diào)用的方法中(它就是調(diào)用的方法里的this對(duì)象)。因此接收對(duì)象也逃逸出了當(dāng)前域;在這個(gè)例子中,這意味著如果逃逸分析分析完這段Java代碼,r1和r2都會(huì)歸類為ArgEscape。

如果就只是這樣的話,那么分配消除的使用場(chǎng)景就很有限了。所幸的是,HotSpot VM能做得更好。我們來仔細(xì)看一下它的字節(jié)碼,看看能發(fā)現(xiàn)什么。

sameArea()方法很小(只有17個(gè)字節(jié)的字節(jié)碼),在本例中也會(huì)被頻繁調(diào)用,因此它是方法內(nèi)聯(lián)(method inlined)的一個(gè)理想對(duì)象。

JVM優(yōu)化之逃逸分析與分配消除

這個(gè)方法又調(diào)用了兩次area()方法(這個(gè)也是可以內(nèi)聯(lián)的):

JVM優(yōu)化之逃逸分析與分配消除

通過JITWatch或者PrintCompilation可以看到,area()方法的調(diào)用的確被內(nèi)聯(lián)進(jìn)了調(diào)用方sameArea()方法里,而sameArea()又被內(nèi)聯(lián)到了main()方法的循環(huán)體中。JITWatch為內(nèi)聯(lián)方法提供了一個(gè)很方便的圖形化展示(如圖一所示)。

JVM優(yōu)化之逃逸分析與分配消除

請(qǐng)記住Java HotSpot VM的JIT編譯器的優(yōu)化順序也是很重要的。方法內(nèi)聯(lián)是最早的優(yōu)化,也被稱為網(wǎng)關(guān)優(yōu)化(gateway optimization),因?yàn)樗紫劝严嚓P(guān)聯(lián)的代碼都聚合在了一起,為其它優(yōu)化打開了大門。http://dalian.huodong.dqccc.com/exposition/detail-2237268.html

鄭州男人不孕不育醫(yī)院:http://www.xbzztj.com/

現(xiàn)在sameArea()方法和area()方法都被內(nèi)聯(lián)進(jìn)來了,方法域的問題不復(fù)存在,所有的變量都只在main方法的作用域內(nèi)了。也就是說逃逸分析不會(huì)再把r1和r2視作ArgEscape類型:方法內(nèi)聯(lián)之后,它們現(xiàn)在都被歸類為NoEscape。

這個(gè)結(jié)果看起來可能有悖常理,不過你需要記住的是JIT編譯器并不是通過原始代碼來進(jìn)行優(yōu)化的。如果不知道這點(diǎn),就搞不清楚哪些情況能夠進(jìn)行逃逸分析。

前面的例子中,這些對(duì)象的分配都不會(huì)在堆上進(jìn)行了,會(huì)把它們的字段拆解成獨(dú)立的值。寄存器分配器通常會(huì)把拆解出來的字段直接放到寄存器中,不過如果沒有足夠可用的寄存器,那剩下的字段會(huì)被存儲(chǔ)到棧上。這種情況被稱為棧溢出(stack spill,注:和stack overflow不同)。

在逃逸分析開啟和關(guān)閉的模式下分別運(yùn)行這個(gè)程序,再觀察下GC的活動(dòng),你就能看到密集循環(huán)中堆分配消除的巨大威力。

在現(xiàn)代JVM中逃逸分析是默認(rèn)開啟的,得通過JVM參數(shù)-XX:-DoEscapeAnalysis來關(guān)掉它。

下面是開啟了逃逸分析之后的GC日志(一些細(xì)節(jié)刪除了):

JVM優(yōu)化之逃逸分析與分配消除

從日志中可以看到根本沒有發(fā)生GC事件——只是在進(jìn)程退出時(shí)往日志里記錄了下堆的摘要信息。如果再看下關(guān)閉逃逸分析后的運(yùn)行日志,情況就截然不同了:

JVM優(yōu)化之逃逸分析與分配消除

這里可以很清楚地看到,由于Eden區(qū)空間滿了,導(dǎo)致了內(nèi)存分配失敗、需要進(jìn)行垃圾回收,因此觸發(fā)了GC事件。

結(jié)論

逃逸分析是Java HotSpot VM引入的一項(xiàng)非常有用的升級(jí)。這項(xiàng)功能仍在開發(fā)階段時(shí),實(shí)際測(cè)試中它帶來的性能提升就有3%到6%。

對(duì)于那些對(duì)平臺(tái)特性的實(shí)現(xiàn)過程和原理感興趣的開發(fā)人員來說,逃逸分析有個(gè)很有意思的特點(diǎn):這項(xiàng)特性依賴于其它優(yōu)化(自動(dòng)內(nèi)聯(lián)),不然用處不大。

新聞標(biāo)題:JVM優(yōu)化之逃逸分析與分配消除
新聞來源:http://bm7419.com/article20/pcdpjo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、移動(dòng)網(wǎng)站建設(shè)服務(wù)器托管、網(wǎng)站制作、自適應(yīng)網(wǎng)站商城網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)