JVM棧分配對(duì)象內(nèi)存與逃逸分析原理分析(Escape Analysis)

      網(wǎng)友投稿 805 2022-05-30

      1 逃逸分析

      JVM中較前沿的優(yōu)化技術(shù),它與類(lèi)型繼承關(guān)系分析一樣,并非直接優(yōu)化代碼,而是為其他優(yōu)化措施提供依據(jù)的分析技術(shù)。

      1.1 基本原理

      分析對(duì)象動(dòng)態(tài)作用域,當(dāng)一個(gè)對(duì)象在方法里面被定義后,它可能

      被外部方法所引用

      例如作為調(diào)用參數(shù)傳遞給其他方法,稱(chēng)為方法逃逸

      被外部線程訪問(wèn)

      譬如賦值給可以在其他線程中訪問(wèn)的實(shí)例變量,稱(chēng)為線程逃逸

      從不逃逸 =》方法逃逸 =》線程逃逸,稱(chēng)為對(duì)象由低到高的不同逃逸程度。

      如果能證明一個(gè)對(duì)象不會(huì)逃逸到方法或線程外(即別的方法或線程無(wú)法通過(guò)任何途徑訪問(wèn)到該對(duì)象),或逃逸程度較低(只逃逸出方法而不逃逸出線程),則可能為這個(gè)對(duì)象實(shí)例采取不同程度的優(yōu)化,如:

      2 棧上分配(Stack Allocations)

      由于復(fù)雜度等原因,HotSpot中目前暫時(shí)還沒(méi)有做這項(xiàng)優(yōu)化,但一些其他的虛擬機(jī)(如Excelsior JET)使用了該優(yōu)化。

      JVM中,Java堆上分配創(chuàng)建對(duì)象的內(nèi)存空間是常識(shí),Java堆中的對(duì)象對(duì)各線程共享可見(jiàn),只要持有該對(duì)象的引用,就可訪問(wèn)到堆中存儲(chǔ)的對(duì)象數(shù)據(jù)。

      虛擬機(jī)的GC子系統(tǒng)會(huì)回收堆中不再使用的對(duì)象,但回收動(dòng)作無(wú)論是標(biāo)記篩選出可回收對(duì)象,還是回收和整理內(nèi)存,都需耗費(fèi)大量資源。

      如果確定一個(gè)對(duì)象不會(huì)逃逸出線程,那讓該對(duì)象在棧上分配內(nèi)存是個(gè)不錯(cuò)主意,對(duì)象所占用內(nèi)存空間就可隨棧幀出棧而銷(xiāo)毀。

      在一般應(yīng)用中,完全不會(huì)逃逸的局部對(duì)象和不會(huì)逃逸出線程的對(duì)象所占的比例很大,如果能使用棧上分配,那大量對(duì)象就會(huì)隨方法結(jié)束而自動(dòng)銷(xiāo)毀,GC子系統(tǒng)壓力會(huì)下降很多。棧上分配可支持方法逃逸,但不能支持線程逃逸。

      3 標(biāo)量替換(Scalar Replacement)

      若一個(gè)數(shù)據(jù)已經(jīng)無(wú)法再分解成更小數(shù)據(jù)來(lái)表示,JVM中基礎(chǔ)數(shù)據(jù)類(lèi)型都不能再進(jìn)一步分解,這些數(shù)據(jù)可被稱(chēng)為標(biāo)量。

      相對(duì)的,如果一個(gè)數(shù)據(jù)可以繼續(xù)分解,那它就被稱(chēng)為聚合量(Aggregate),Java 中的對(duì)象就是典型的聚合量。如果把一個(gè)Java對(duì)象拆散,根據(jù)程序訪問(wèn)的情況,將其用到的成員變量恢復(fù)為原始類(lèi)型來(lái)訪問(wèn),該過(guò)程就稱(chēng)為標(biāo)量替換。

      假如逃逸分析能夠證明一個(gè)對(duì)象不會(huì)被方法外部訪問(wèn),并且該對(duì)象可被分解,那么程序真正執(zhí)行時(shí)將可能不去創(chuàng)建該對(duì)象,而改為直接創(chuàng)建它的若干個(gè)被這方法使用的成員變量代替。

      將對(duì)象拆分后,除可讓對(duì)象的成員變量在棧上 (棧上存儲(chǔ)的數(shù)據(jù),很大機(jī)會(huì)被虛擬機(jī)分配至物理機(jī)器的高速寄存器中存儲(chǔ))分配和讀寫(xiě)外,還可為后續(xù)進(jìn)步優(yōu)化創(chuàng)建條件。

      標(biāo)量替換可視作棧上分配一種特例,實(shí)現(xiàn)更簡(jiǎn)單(不用考慮對(duì)象完整結(jié)構(gòu)的分配),但對(duì)逃逸程度的要求更高,它不允許對(duì)象逃逸出方法范圍內(nèi)。

      4 同步消除(Synchronization Elimination)

      線程同步本身是一個(gè)相對(duì)耗時(shí)過(guò)程,如果逃逸分析能確定一個(gè)變量不會(huì)逃逸出線程,無(wú)法被其他線程訪問(wèn),那么該變量讀寫(xiě)肯定不會(huì)有競(jìng)爭(zhēng), 對(duì)該變量實(shí)施的同步措施也可安全消除。

      關(guān)于逃逸分析的研究論文早在1999年就已經(jīng)發(fā)表,但到JDK 6,HotSpot才開(kāi)始支持初步逃逸分析,到現(xiàn)在這優(yōu)化技術(shù)尚未足夠成熟。

      不成熟的原因主要是逃逸分析的計(jì)算成本非常高,甚至不能保證逃逸分析帶來(lái)的性能收益會(huì)高于它的消耗。要百分之百準(zhǔn)確地判斷一個(gè)對(duì)象是否會(huì)逃逸,需要進(jìn)行一系列復(fù)雜的數(shù)據(jù)流敏感的過(guò)程間分析,才能確定程序各個(gè)分支執(zhí)行時(shí)對(duì)此對(duì)象的影響。

      前面介紹即時(shí)編譯、提前編譯優(yōu)劣勢(shì)時(shí)提到了過(guò)程間分析這種大壓力的分析算法正是即時(shí)編譯的弱項(xiàng)??梢栽囅胍幌拢绻右莘治鐾戤吅蟀l(fā)現(xiàn)幾乎找不到幾個(gè)不逃逸的對(duì)象, 那這些運(yùn)行期耗用的時(shí)間就白白浪費(fèi)了,所以目前虛擬機(jī)只能采用不那么準(zhǔn)確,但時(shí)間壓力相對(duì)較小的算法來(lái)完成分析。

      C和C++原生支持棧上分配(不使用new即可),而C#也支持值類(lèi)型,可以自然做到標(biāo)量替換(但并不會(huì)對(duì)引用類(lèi)型做這種優(yōu)化)。

      在靈活運(yùn)用棧內(nèi)存方面,確實(shí)是Java的弱項(xiàng)。

      在現(xiàn)在仍處于實(shí)驗(yàn)階段的Valhalla項(xiàng)目里,設(shè)計(jì)了新的inline關(guān)鍵字用于定義Java的內(nèi)聯(lián)類(lèi)型, 目的是實(shí)現(xiàn)與C#中值類(lèi)型相對(duì)標(biāo)的功能。有了這個(gè)標(biāo)識(shí)與約束,以后逃逸分析做起來(lái)就會(huì)簡(jiǎn)單很多。

      下面通過(guò)一系列Java偽代碼的變化過(guò)程來(lái)模擬逃逸分析是如何工作的,向讀者展示逃逸分析能夠?qū)崿F(xiàn)的效果。

      初始代碼如下所示:

      // 完全未優(yōu)化代碼 public int test(int x) { int xx = x + 2; Point p = new Point(xx, 42); return p.getX(); }

      1

      2

      3

      4

      5

      6

      此處省略了Point類(lèi)的代碼。第一步,將Point的構(gòu)造函數(shù)和getX()方法進(jìn)行內(nèi)聯(lián)優(yōu)化:

      // 步驟1:構(gòu)造函數(shù)內(nèi)聯(lián)后的樣子 public int test(int x) { int xx = x + 2; Point p = point_memory_alloc(); // 在堆中分配P對(duì)象的示意方法 p.x = xx; // Point構(gòu)造函數(shù)被內(nèi)聯(lián)后的樣子 p.y = 42 return p.x; // Point::getX()被內(nèi)聯(lián)后的樣子 }

      1

      JVM棧上分配對(duì)象內(nèi)存與逃逸分析原理分析(Escape Analysis)

      2

      3

      4

      5

      6

      7

      8

      第二步,經(jīng)過(guò)逃逸分析,發(fā)現(xiàn)在整個(gè)test()方法的范圍內(nèi)Point對(duì)象實(shí)例不會(huì)發(fā)生任何程度的逃逸, 這樣可以對(duì)它進(jìn)行標(biāo)量替換優(yōu)化,把其內(nèi)部的x和y直接置換出來(lái),分解為test()方法內(nèi)的局部變量,從 而避免Point對(duì)象實(shí)例被實(shí)際創(chuàng)建,優(yōu)化后的結(jié)果如下所示:

      // 步驟2:標(biāo)量替換后的樣子 public int test(int x) { int xx = x + 2; int px = xx; int py = 42 return px; }

      1

      2

      3

      4

      5

      6

      7

      第三步,通過(guò)數(shù)據(jù)流分析,發(fā)現(xiàn)py的值其實(shí)對(duì)方法不會(huì)造成任何影響,那就可以放心地去做無(wú)效 代碼消除得到最終優(yōu)化結(jié)果,如下所示:

      // 步驟3:做無(wú)效代碼消除后的樣子 public int test(int x) { return x + 2; }

      1

      2

      3

      4

      從測(cè)試結(jié)果來(lái)看,實(shí)施逃逸分析后的程序在MicroBenchmarks中往往能得到不錯(cuò)的成績(jī),但是在實(shí)際的應(yīng)用程序中,尤其是大型程序中反而發(fā)現(xiàn)實(shí)施逃逸分析可能出現(xiàn)效果不穩(wěn)定的情況,或分析過(guò)程耗時(shí)但卻無(wú)法有效判別出非逃逸對(duì)象而導(dǎo)致性能(即時(shí)編譯的收益)下降,所以曾經(jīng)在很長(zhǎng)的一段時(shí) 間里,即使是服務(wù)端編譯器,也默認(rèn)不開(kāi)啟逃逸分析(從JDK 6 Update 23開(kāi)始,服務(wù)端編譯器中開(kāi)始才默認(rèn)開(kāi)啟逃逸分析。

      ),甚至在某些版本(如JDK 6 Update 18)中還曾完全禁止這項(xiàng)優(yōu)化,一直到JDK 7時(shí)這項(xiàng)優(yōu)化才成為服務(wù)端編譯器默認(rèn)開(kāi)啟的選項(xiàng)。如果有需要,或者確認(rèn)對(duì)程序運(yùn)行有益,用戶(hù)也可以使用參數(shù)-XX:+DoEscapeAnalysis來(lái)手動(dòng)開(kāi)啟逃逸分析, 開(kāi)啟之后可以通過(guò)參數(shù)-XX:+PrintEscapeAnalysis來(lái)查看分析結(jié)果。有了逃逸分析支持之后,用戶(hù)可使用參數(shù)-XX:+EliminateAllocations來(lái)開(kāi)啟標(biāo)量替換,使用+XX:+EliminateLocks來(lái)開(kāi)啟同步消 除,使用參數(shù)-XX:+PrintEliminateAllocations查看標(biāo)量的替換情況。

      盡管目前逃逸分析技術(shù)仍在發(fā)展之中,未完全成熟,但它是即時(shí)編譯器優(yōu)化技術(shù)的一個(gè)重要前進(jìn) 方向,在日后的Java虛擬機(jī)中,逃逸分析技術(shù)肯定會(huì)支撐起一系列更實(shí)用、有效的優(yōu)化技術(shù)。

      參考

      《深入理解 Java 虛擬機(jī)》

      Java JVM

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶(hù)投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:【直播回顧】企業(yè)協(xié)同管理新模式,看華為云攜手致遠(yuǎn)互聯(lián)加速企業(yè)數(shù)智轉(zhuǎn)型!
      下一篇:【Java核心面試寶典】Day16、“計(jì)算機(jī)網(wǎng)絡(luò)協(xié)議層次及服務(wù)類(lèi)型”面試題!???
      相關(guān)文章
      亚洲AV无码专区在线厂| 亚洲成av人片不卡无码| 久久亚洲AV成人出白浆无码国产| 亚洲成A∨人片天堂网无码| 国产成人精品亚洲2020| 亚洲日产2021三区| 亚洲天堂电影在线观看| 亚洲一区二区三区在线| 亚洲性色高清完整版在线观看| 亚洲精品无码久久久久去q| 情人伊人久久综合亚洲| 久久亚洲精品AB无码播放| 亚洲精品国产精品乱码不99| 亚洲高清国产AV拍精品青青草原| 人人狠狠综合久久亚洲婷婷| 久久精品国产亚洲av成人| 亚洲国产精品免费视频| 噜噜噜亚洲色成人网站∨| 亚洲日本香蕉视频| 亚洲精品美女网站| 亚洲av成人一区二区三区在线播放| 日本亚洲中午字幕乱码| 亚洲人妻av伦理| 亚洲精品午夜无码电影网| 亚洲卡一卡2卡三卡4卡无卡三 | 911精品国产亚洲日本美国韩国| 亚洲美女在线观看播放| 亚洲国产电影在线观看| 亚洲中文字幕无码mv| 亚洲AV无码一区二区三区牲色| 亚洲熟妇少妇任你躁在线观看无码| 美腿丝袜亚洲综合| 久久久久亚洲AV成人无码网站| 久久久无码精品亚洲日韩京东传媒| 亚洲国产成人精品电影| 亚洲色www永久网站| 亚洲日韩在线中文字幕综合| 亚洲性日韩精品一区二区三区| 久久夜色精品国产亚洲| 亚洲视频一区在线播放| 亚洲日韩看片无码电影|