《深入理解Java虛擬機(jī)》讀書筆記7--運(yùn)行期優(yōu)化

記得在大學(xué)剛開始學(xué)習(xí)Java的時(shí)候造虏,也許是為了讓大家好理解遂跟,老師說Java是一門解釋執(zhí)行的語言。但是現(xiàn)在回顧這句話鸵钝,這種說法可能就不是那么準(zhǔn)確了

實(shí)際上疏哗,Java程序在啟動最初是通過解釋器進(jìn)行解釋執(zhí)行的呛讲,但是當(dāng)某個(gè)方法或者代碼運(yùn)行非常頻繁的時(shí)候,虛擬機(jī)就會把這部分代碼視為“熱點(diǎn)代碼”(Hot Spot Code)返奉,在運(yùn)行時(shí)將這部分代碼編譯成平臺相關(guān)的機(jī)器碼贝搁,并且進(jìn)行各種層次的優(yōu)化,以提高熱點(diǎn)代碼的執(zhí)行效率芽偏。完成這種工作的編譯器就是即時(shí)編譯器(Just In Time Compiler雷逆,JIT編譯器)

解釋器與編譯器

解釋器與編譯器各具優(yōu)勢:當(dāng)程序需要迅速啟動和執(zhí)行的時(shí)候,解釋器可以首先發(fā)揮作用哮针,省去編譯時(shí)間,立即執(zhí)行。當(dāng)程序運(yùn)行一段時(shí)間后十厢,編譯器逐漸發(fā)揮作用等太,將熱點(diǎn)代碼編譯成本地代碼,以獲得更高的執(zhí)行效率蛮放。對于一些內(nèi)存緊張的場景(如嵌入式系統(tǒng))缩抡,解釋器有助于節(jié)省內(nèi)存。另外解釋器也可以作為編譯器激進(jìn)優(yōu)化時(shí)的一個(gè)“逃生門”包颁,讓編譯器依據(jù)概率選擇一些在大多數(shù)場景下能夠提升運(yùn)行效率的優(yōu)化手段瞻想,當(dāng)激進(jìn)優(yōu)化的假設(shè)不成立時(shí),再回退到解釋執(zhí)行的狀態(tài)繼續(xù)執(zhí)行娩嚼。HotSpot虛擬機(jī)內(nèi)置了兩個(gè)即時(shí)編譯器蘑险,分別是C1編譯器(Client Compiler)和C2編譯器(Server Compiler)

(1)混合模式(Mixed Mode)

虛擬機(jī)默認(rèn)情況下采用解釋器與其中一個(gè)編譯器配合工作的方式運(yùn)行,這種方式稱為混合模式岳悟。采用哪個(gè)即時(shí)編譯器取決于虛擬機(jī)運(yùn)行的模式(Client模式或者Server模式)佃迄,虛擬機(jī)會依據(jù)自身版本以及硬件性能自動選擇運(yùn)行模式,用戶也可以通過“-client”或者“-server”參數(shù)指定

(2)解釋模式(Interpreted Mode)

可通過“-Xint”參數(shù)強(qiáng)制虛擬機(jī)運(yùn)行于解釋模式贵少,這時(shí)代碼通過解釋方式執(zhí)行呵俏,編譯器完全不介入工作。完全使用解釋方式執(zhí)行滔灶,通常會導(dǎo)致程序性能較差

(3)編譯模式(Compiled Mode)

可通過“-Xcomp”參數(shù)強(qiáng)制虛擬機(jī)運(yùn)行于編譯模式普碎,這時(shí)代碼優(yōu)先采用編譯方式執(zhí)行,但是解釋器仍然需要在編譯無法進(jìn)行的時(shí)候介入執(zhí)行录平。即時(shí)編譯器編譯本地代碼需要占用cpu時(shí)間麻车,要編譯出優(yōu)化程度很高的代碼,則需要花費(fèi)更多的時(shí)間(期間需要收集各種性能監(jiān)控?cái)?shù)據(jù))

為了在程序啟動響應(yīng)速度與運(yùn)行效率之間達(dá)到平衡萄涯,虛擬機(jī)采用了分層編譯(Tiered Compilation)的策略:

第0層:程序解釋執(zhí)行绪氛,解釋器不開啟性能監(jiān)控,可觸發(fā)第1層編譯

第1層:編譯為本地代碼涝影,進(jìn)行簡單可靠的優(yōu)化枣察,如有必要將開啟性能監(jiān)控

第2層:編譯為本地代碼,會啟用一些耗時(shí)較長的優(yōu)化燃逻,甚至?xí)罁?jù)性能監(jiān)控?cái)?shù)據(jù)進(jìn)行一些不可靠的激進(jìn)優(yōu)化

分層編譯的好處就是序目,在系統(tǒng)執(zhí)行初期,執(zhí)行頻率比較高的代碼先被c1編譯器編譯伯襟,以便盡快進(jìn)入編譯執(zhí)行猿涨,然后隨著時(shí)間的推移,執(zhí)行頻率較高的代碼再被c2編譯器編譯姆怪,以達(dá)到最高的性能

編譯對象與觸發(fā)條件

熱點(diǎn)代碼就是被頻繁執(zhí)行的代碼叛赚,符合這個(gè)條件的代碼通常有兩類:被多次調(diào)用的方法澡绩、被多次執(zhí)行的循環(huán)體。判斷一段代碼是否是熱點(diǎn)代碼俺附,這種行為稱為熱點(diǎn)探測(Hot Spot Detection)肥卡,主要有兩種方式:

(1)基于采樣的熱點(diǎn)探測(Sample Based Hot Spot Detection):采用這種方式,虛擬機(jī)會周期性的檢查各個(gè)線程的棧頂事镣,如果發(fā)現(xiàn)某些方法經(jīng)常出現(xiàn)在棧頂步鉴,那么這些方法就是熱點(diǎn)方法。這種方式的優(yōu)點(diǎn)是簡單高效璃哟、容易獲取調(diào)用關(guān)系氛琢。缺點(diǎn)是很難精確地確認(rèn)一個(gè)方法的熱度

(2)基于計(jì)數(shù)器的熱點(diǎn)探測(Counter Based Hot Spot Detection):采用這種方式,虛擬機(jī)會為每個(gè)方法(甚至是代碼塊)建立計(jì)數(shù)器來統(tǒng)計(jì)執(zhí)行次數(shù)随闪,如果執(zhí)行次數(shù)超過一定閾值阳似,那么就認(rèn)定是熱點(diǎn)方法。這種方式的優(yōu)點(diǎn)是更加精確嚴(yán)謹(jǐn)蕴掏。缺點(diǎn)是實(shí)現(xiàn)相對繁瑣障般,切不能直接獲得調(diào)用關(guān)系

HotSpot虛擬機(jī)采用上述第二種熱點(diǎn)探測方法。它為每個(gè)方法準(zhǔn)備了兩類計(jì)數(shù)器

(1)方法調(diào)用計(jì)數(shù)器(Invocation Counter):

當(dāng)一個(gè)方法被調(diào)用時(shí)盛杰,會首先檢查該方法是否有被JIT編譯過的版本挽荡,如果有,則使用被JIT編譯過的版本執(zhí)行即供。如果沒有定拟,則將此方法的調(diào)用計(jì)數(shù)器值加1,然后檢查方法調(diào)用計(jì)數(shù)器與回邊計(jì)數(shù)器值之和是否超過方法調(diào)用計(jì)數(shù)器閾值逗嫡。如果已經(jīng)超過閾值青自,那么將會向JIT編譯器發(fā)起針對該方法進(jìn)行編譯的請求。之后驱证,執(zhí)行引擎不會同步等待編譯結(jié)果延窜,而是繼續(xù)按照解釋執(zhí)行的方式執(zhí)行代碼。當(dāng)編譯完成后抹锄,該方法的調(diào)用入口地址會被改寫成新地址逆瑞,下一次調(diào)用將會使用該編譯版本

如果不做特殊設(shè)置,那么調(diào)用計(jì)數(shù)統(tǒng)計(jì)的并非絕對次數(shù)伙单,而是一個(gè)相對的頻率获高,就是一段時(shí)間內(nèi)被調(diào)用的次數(shù)。當(dāng)超過一定時(shí)間限度吻育,如果方法調(diào)用次數(shù)沒有超過閾值念秧,那么計(jì)數(shù)器值將減半,這個(gè)過程叫做方法調(diào)用計(jì)數(shù)器的熱度衰減(Counter Decay)布疼,而這段時(shí)間就叫做方法調(diào)用計(jì)數(shù)統(tǒng)計(jì)的半衰期(Counter Half Life Time)

(2)回邊計(jì)數(shù)器(Back Edge Counter):

在字節(jié)碼中摊趾,遇到控制流向回跳轉(zhuǎn)的指令稱為“回邊”(Back Edge)币狠。簡單來說,回邊計(jì)數(shù)器的作用就是統(tǒng)計(jì)循環(huán)體被執(zhí)行的次數(shù)砾层∽苎埃回邊計(jì)數(shù)器用于觸發(fā)OSR編譯(On-Stack Replacement,關(guān)于OSR可參考:OSR是怎樣的機(jī)制

當(dāng)解釋器遇到一條回邊指令時(shí)梢为,會首先檢查將要執(zhí)行的代碼是否有被編譯過的版本,如果有轰坊,則使用被編譯過的版本執(zhí)行铸董。如果沒有,則將回邊計(jì)數(shù)器值加1肴沫,然后檢查方法調(diào)用計(jì)數(shù)器與回邊計(jì)數(shù)器值之和是否超過回邊計(jì)數(shù)器閾值粟害。如果已經(jīng)超過閾值,那么將會提交一個(gè)OSR編譯請求颤芬,并且把回邊計(jì)數(shù)器的值降低一些悲幅。之后,執(zhí)行引擎不會同步等待編譯結(jié)果站蝠,而是繼續(xù)按照解釋的方式執(zhí)行代碼

回邊計(jì)數(shù)器沒有計(jì)數(shù)熱度衰減汰具,當(dāng)這個(gè)計(jì)數(shù)器溢出的時(shí)候,它會把方法計(jì)數(shù)器也調(diào)整到溢出狀態(tài)菱魔,這樣下次進(jìn)入該方法的時(shí)候就會對方法進(jìn)行編譯

編譯過程

對于C1編譯器和C2編譯器留荔,編譯過程有所不同

C1編譯器:主要關(guān)注點(diǎn)在于局部性優(yōu)化(而不是耗時(shí)的全局優(yōu)化),是一個(gè)簡單快速的三段式編譯器

(1)第一階段:首先會完成一些基礎(chǔ)優(yōu)化澜倦,如方法內(nèi)聯(lián)聚蝶、常量傳播等。之后藻治,一個(gè)平臺獨(dú)立的前端碘勉,將字節(jié)碼構(gòu)造成一種高級中間代碼表示(High-Level Intermediate Representation,HIR)桩卵。HIR使用靜態(tài)分配(Static Single Assignment验靡,SSA)的方式代表代碼值,這可以使一些在HIR構(gòu)造之中和之后進(jìn)行的優(yōu)化更容易實(shí)現(xiàn)

(2)第二階段:首先在HIR上完成另一些優(yōu)化吸占,如空值檢查消除晴叨、范圍檢查消除等,以便讓HIR達(dá)到更高效的代碼表示形式矾屯。之后兼蕊,一個(gè)平臺相關(guān)的后端,會從HIR中產(chǎn)生低級中間代碼(Low-Level Intermediate Representation件蚕,LIR)

(2)第三階段:在平臺相關(guān)的后端上使用線性掃描法(Linear Scan Register Allocation)在LIR上分配寄存器孙技,并在LIR上做窺孔(Peephole)優(yōu)化产禾,然后產(chǎn)生機(jī)器代碼

C2編譯器:它是一個(gè)充分優(yōu)化過的高級編譯器,會執(zhí)行所有經(jīng)典的優(yōu)化動作牵啦,如無用代碼消除亚情、循環(huán)展開、循環(huán)表達(dá)式外提哈雏、消除公共子表達(dá)式楞件、常量傳播、基本塊重排序等裳瘪。除此之外土浸,還會實(shí)施一些與Java語言特征密切相關(guān)的優(yōu)化,如空值檢查消除彭羹、范圍檢查消除等黄伊。另外還會依據(jù)解釋器或者C1編譯器提供的性能監(jiān)控?cái)?shù)據(jù),進(jìn)行一些不穩(wěn)定的激進(jìn)優(yōu)化派殷,如守護(hù)內(nèi)聯(lián)还最、分支頻率預(yù)測等

C2編譯器的編譯速度雖然相對來說比較緩慢,但是依然遠(yuǎn)超傳統(tǒng)的靜態(tài)優(yōu)化編譯器毡惜。而且它相比C1編譯器的編譯質(zhì)量更高拓轻,可以降低本地代碼執(zhí)行時(shí)間

編譯優(yōu)化技術(shù)

相比于解釋執(zhí)行,虛擬機(jī)團(tuán)隊(duì)把更多的精力放在了即時(shí)編譯器上经伙,因此通常來說悦即,被即時(shí)編譯器優(yōu)化后的本地代碼比解釋執(zhí)行的效率更高

我們首先通過一個(gè)簡單的例子,來直觀的感受一下幾種優(yōu)化技術(shù)是如何發(fā)揮作用的橱乱。在這個(gè)例子中辜梳,我們通過Java代碼作為偽代碼來模擬一下優(yōu)化效果(實(shí)際的編譯優(yōu)化不在Java語言層面,甚至不在字節(jié)碼層面泳叠,而是在某種中間代碼或者機(jī)器碼之上)作瞄,目的僅是為了方便展示。首先來看一下原始的Java代碼:

方法內(nèi)聯(lián)(Method Inlining)

首先要進(jìn)行的優(yōu)化是方法內(nèi)聯(lián)危纫,它的重要性要高于其他優(yōu)化宗挥。它的主要目的有兩個(gè):

一個(gè)是去除方法調(diào)用的成本(棧幀的開銷,關(guān)于棧幀方面的內(nèi)容种蝶,可參考本系列文章:字節(jié)碼執(zhí)行引擎

另一個(gè)是為其他優(yōu)化做好基礎(chǔ)契耿,方法內(nèi)聯(lián)膨脹之后,可以便于在更大范圍內(nèi)采取后續(xù)優(yōu)化手段螃征,從而獲得更好的優(yōu)化效果

因此搪桂,方法內(nèi)聯(lián)通常放在優(yōu)化手段的最前列。經(jīng)過方法內(nèi)聯(lián)后的偽代碼如下:

冗余訪問消除(Redundant Loads Elimination)

第二步進(jìn)行冗余訪問消除,偽代碼如下:

復(fù)寫傳播(Copy Propagation)

第三步是復(fù)寫傳播踢械,在我們代碼中沒有必要額外使用一個(gè)變量“y”酗电,因此偽代碼如下:

無用代碼消除(Dead Code Elimination)

第四步進(jìn)行無用代碼消除,無用代碼是指永遠(yuǎn)不會被執(zhí)行的代碼或者完全沒有意義的代碼内列,在我們的例子中撵术,“x = x;”是沒有意義的,话瞧,因此偽代碼如下:

經(jīng)過四次優(yōu)化后嫩与,最終的代碼比源代碼精簡很多(體現(xiàn)在機(jī)器碼上差距會更明顯),執(zhí)行效率也會更高交排。編譯器要實(shí)現(xiàn)這些優(yōu)化也許會比較復(fù)雜蕴纳,但是基本原理卻比較簡單

下面我們看幾項(xiàng)最有代表性的優(yōu)化技術(shù)是如何運(yùn)作的:

(1)公共子表達(dá)式消除

公共子表達(dá)式消除是一種被廣泛應(yīng)用于各種編譯器的經(jīng)典優(yōu)化技術(shù),它的主要思想是:假設(shè)一個(gè)表達(dá)式E已經(jīng)被計(jì)算過个粱,并且從先前計(jì)算到現(xiàn)在,E中的變量一直都沒有再變化過翻翩,那么E的這次出現(xiàn)就成為了公共子表達(dá)式都许,那么就沒有必要再次對E進(jìn)行計(jì)算,只要直接使用先前的值替代E就可以了嫂冻。假設(shè)存在下面這段代碼:

int a = (b * c) * 3 + d + (d + c * b);

編譯器發(fā)現(xiàn)胶征,“b * c”和?“c * b”是一樣的表達(dá)式,并且在運(yùn)算期間b和c的值都沒有再發(fā)生變化桨仿,那么這段代碼將被優(yōu)化為:

int a = E * 3 + d + (d + E);

之后睛低,編譯器還有可能進(jìn)行一項(xiàng)叫做代數(shù)化簡(Algebraic Simplification)的優(yōu)化,被優(yōu)化后的代碼如下:

int a = E * 4 + d * 2;

經(jīng)過公共子表達(dá)式消除優(yōu)化后的代碼顯然比原始代碼更加簡潔服傍,效率更高

(2)數(shù)組邊界檢查消除

在Java語言中钱雷,假如有一個(gè)數(shù)組a[],在訪問數(shù)組元素的時(shí)候吹零,虛擬機(jī)將自動進(jìn)行上下邊界的檢查罩抗。這個(gè)對于開發(fā)者是好事,但是對于虛擬機(jī)來說灿椅,如果執(zhí)行擁有大量數(shù)組訪問的代碼套蒂,這肯定是一種性能負(fù)擔(dān)

在一些情況下,數(shù)組邊界檢查在運(yùn)行時(shí)茫蛹,并非一次不漏的運(yùn)行操刀,例如:數(shù)組下標(biāo)是一個(gè)常量,只要在編譯期根據(jù)數(shù)據(jù)流分析確定這個(gè)數(shù)組下標(biāo)沒有越界婴洼,那么在運(yùn)行時(shí)就無需再做檢查了骨坑。還有一種情況是在循環(huán)中通過循環(huán)變量來訪問數(shù)組元素,只要在編譯期根據(jù)數(shù)據(jù)流分析確定循環(huán)變量沒有越界柬采,那么在整個(gè)循環(huán)中就完全不需要再做檢查

站在更高的維度上來看卡啰,類似數(shù)組邊界檢查這樣的安全檢查還有很多(如空指針檢查静稻、除數(shù)為0檢查等)。這些檢查的確方便了程序開發(fā)匈辱,令程序更加安全振湾,但確實(shí)是一種隱式開銷。為了降低這種開銷亡脸,除了如數(shù)組邊界檢查消除這種盡可能把運(yùn)行時(shí)檢查提前到編譯期的思路外押搪,還有一種思路是隱式異常處理(Java中空指針檢查、除數(shù)為0檢查采用這種思路)

舉例說明浅碾,比如訪問一個(gè)對象的某個(gè)屬性大州,加入采用運(yùn)行時(shí)檢查,那么虛擬機(jī)的偽代碼如下:

在采用隱式異常處理優(yōu)化后垂谢,虛擬機(jī)的偽代碼如下:

虛擬機(jī)會注冊一個(gè)segment_fault的異常處理器厦画,這樣當(dāng)a不為null的時(shí)候,a.value不會額外消耗一次安全檢查的開銷滥朱。代價(jià)是當(dāng)a真的為null時(shí)根暑,需要轉(zhuǎn)入異常處理器中處理并拋出NullPointerException,這個(gè)動作必須由用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài)徙邻,等處理完成后再轉(zhuǎn)回用戶態(tài)排嫌,開銷遠(yuǎn)比一次安全檢查要大。當(dāng)a極少為空的時(shí)候缰犁,這種優(yōu)化是值得的淳地,但是當(dāng)a經(jīng)常為空,這種優(yōu)化反而更慢帅容。但是颇象,虛擬機(jī)會根據(jù)運(yùn)行時(shí)收集到的數(shù)據(jù)自動選擇更優(yōu)的方案

(3)方法內(nèi)聯(lián)

前面已經(jīng)通過例子介紹過方法內(nèi)聯(lián),它是編譯器最重要的優(yōu)化手段之一并徘,作用除了消除方法調(diào)用外夯到,更重要的意義在于為后續(xù)其他優(yōu)化建立良好的基礎(chǔ)

例如下面這段代碼,如果不做方法內(nèi)聯(lián)饮亏,根本無法發(fā)現(xiàn)這兩個(gè)方法的代碼都是沒有意義的耍贾,也就無法做無用代碼消除的優(yōu)化

方法內(nèi)聯(lián)看似就是把目標(biāo)方法的代碼復(fù)制到發(fā)起調(diào)用的方法代碼中,但實(shí)際上Java虛擬機(jī)對方法內(nèi)聯(lián)的處理遠(yuǎn)比看上去復(fù)雜路幸,這個(gè)復(fù)雜主要來源于對虛方法的處理(關(guān)于分派方面的內(nèi)容荐开,可以參看本系列文章:字節(jié)碼執(zhí)行引擎)。對于一個(gè)虛方法简肴,編譯期做方法內(nèi)聯(lián)根本無法確定應(yīng)該使用哪個(gè)方法版本

為了解決虛方法內(nèi)聯(lián)的問題晃听,Java虛擬機(jī)團(tuán)隊(duì)引入了一種稱為“類型繼承關(guān)系分析”(Class Hierarchy Analysis,CHA)的技術(shù)。這是一種基于整個(gè)應(yīng)用程序的類型分析技術(shù)能扒,用于確定目前已經(jīng)加載的類中佣渴,某個(gè)接口是否有多于一種的實(shí)現(xiàn)、某個(gè)類是否有子類初斑、子類是否為抽象類等信息

編譯器在進(jìn)行方法內(nèi)聯(lián)時(shí)辛润,如果不是虛方法,那么可以直接進(jìn)行內(nèi)聯(lián)见秤,這種內(nèi)聯(lián)是穩(wěn)定的砂竖。如果是虛方法,則會向CHA查詢此方法是否有多個(gè)版本可供選擇鹃答。如果只有一個(gè)版本乎澄,那么也可以進(jìn)行內(nèi)聯(lián),但是這種內(nèi)聯(lián)屬于激進(jìn)優(yōu)化测摔。后續(xù)程序執(zhí)行過程中置济,如果虛擬機(jī)一直沒有加載會導(dǎo)致該方法接受者繼承關(guān)系發(fā)生變化的類,那么這個(gè)內(nèi)聯(lián)優(yōu)化就一直可以使用下去锋八。反之浙于,就要放棄這個(gè)內(nèi)聯(lián)優(yōu)化,需要退回到解釋執(zhí)行查库,或者重新編譯

如果向CHA查詢出多個(gè)版本,編譯器則會使用內(nèi)聯(lián)緩存(Inline Cache)來完成方法內(nèi)聯(lián)黄琼。它的原理大致是:未發(fā)生方法調(diào)用前樊销,內(nèi)聯(lián)緩存狀態(tài)為空,當(dāng)?shù)谝淮握{(diào)用發(fā)生后脏款,緩存記錄下方法接收者版本信息围苫,并且每次調(diào)用前都比較版本信息,如果版本一致撤师,則這個(gè)內(nèi)聯(lián)可以繼續(xù)使用剂府,否則會取消內(nèi)聯(lián),查找虛方法表進(jìn)行方法分派

可以看出剃盾,由于Java是一門面向?qū)ο蟮恼Z言腺占,Java對象的方法默認(rèn)就是虛方法,因此在很多情況下痒谴,內(nèi)聯(lián)優(yōu)化都是一種激進(jìn)的優(yōu)化方式衰伯。類似的激進(jìn)優(yōu)化方式還包括隱式異常處理、極小概率使用的分支會被移除等积蔚,當(dāng)真的出現(xiàn)小概率事件意鲸,再退回到解釋執(zhí)行,或者重新編譯

(4)逃逸分析

與CHA一樣,逃逸分析并非直接優(yōu)化手段怎顾,而是為其他優(yōu)化提供依據(jù)的分析技術(shù)读慎。逃逸分析的基本行為就是分析對象動態(tài)作用域:當(dāng)一個(gè)對象在方法中被定義后,它可能被外部方法引用(比如作為方法參數(shù)傳遞到其他方法中)槐雾,這種稱為方法逃逸夭委。還有可能被外部線程引用(比如賦值給類變量或在其他線程中訪問該變量),這種稱為線程逃逸蚜退。如果可以證明該對象不會逃逸到方法或線程外闰靴,則可能對該變量進(jìn)行一些高效的優(yōu)化,比如:

棧上分配(Stack Allocation)

對象在堆中分配钻注,這是大家的共識蚂且。堆中分配的對象,可以被各個(gè)線程共享幅恋。GC可以對堆中不再使用的對象進(jìn)行回收杏死,但是GC需要額外耗費(fèi)資源(關(guān)于GC方面的內(nèi)容,可以參看本系列文章:垃圾收集與內(nèi)存分配

一般情況下捆交,大多數(shù)局部對象都是不會逃逸的淑翼,對于這部分對象,如果采用棧上分配品追,那么對象所占的內(nèi)存就可以隨著方法調(diào)用的結(jié)束隨棧幀的出棧而被回收(關(guān)于棧幀方面的內(nèi)容玄括,可參考本系列文章:字節(jié)碼執(zhí)行引擎)。這樣可以大幅減輕GC負(fù)擔(dān)

同步消除(Synchronization Elimination)

線程同步本身是一個(gè)相對耗時(shí)的過程肉瓦。如果可以確定一個(gè)變量不會逃逸出線程遭京,那么自然也就不再需要做同步

標(biāo)量替代(Scalar Replacement)

標(biāo)量是指數(shù)據(jù)已經(jīng)無法分解成更小的數(shù)據(jù)來表示,Java中的原始數(shù)據(jù)類型就屬于標(biāo)量泞莉,相對的哪雕,對象類型就是聚合量。如果把一個(gè)對象拆散鲫趁,將其使用到的成員變量恢復(fù)成原始類型的方式就是標(biāo)量替換

如果一個(gè)對象不會被外部訪問斯嚎,并且這個(gè)對象可以被拆散,那么虛擬機(jī)可能不會真正創(chuàng)建這個(gè)對象挨厚,而是改為創(chuàng)建它的成員變量來替代堡僻。對象被標(biāo)量替換后,這些成員變量除了可以進(jìn)行棧上分配疫剃,還可以為后續(xù)優(yōu)化創(chuàng)造條件

思維導(dǎo)圖:

筆記7結(jié)束

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末苦始,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子慌申,更是在濱河造成了極大的恐慌陌选,老刑警劉巖理郑,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異咨油,居然都是意外死亡您炉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門役电,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赚爵,“玉大人,你說我怎么就攤上這事法瑟〖较ィ” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵霎挟,是天一觀的道長窝剖。 經(jīng)常有香客問我,道長酥夭,這世上最難降的妖魔是什么赐纱? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮熬北,結(jié)果婚禮上疙描,老公的妹妹穿的比我還像新娘。我一直安慰自己讶隐,他們只是感情好起胰,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著巫延,像睡著了一般效五。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烈评,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天火俄,我揣著相機(jī)與錄音犯建,去河邊找鬼讲冠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛适瓦,可吹牛的內(nèi)容都是我干的竿开。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼玻熙,長吁一口氣:“原來是場噩夢啊……” “哼否彩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嗦随,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤列荔,失蹤者是張志新(化名)和其女友劉穎敬尺,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贴浙,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砂吞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了崎溃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜻直。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖袁串,靈堂內(nèi)的尸體忽然破棺而出概而,到底是詐尸還是另有隱情,我是刑警寧澤囱修,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布赎瑰,位于F島的核電站,受9級特大地震影響蔚袍,放射性物質(zhì)發(fā)生泄漏乡范。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一啤咽、第九天 我趴在偏房一處隱蔽的房頂上張望晋辆。 院中可真熱鬧,春花似錦宇整、人聲如沸瓶佳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霸饲。三九已至,卻和暖如春臂拓,著一層夾襖步出監(jiān)牢的瞬間厚脉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工胶惰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留傻工,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓孵滞,卻偏偏與公主長得像中捆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子坊饶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容