亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JVM:晚期(運(yùn)行期)優(yōu)化的深入理解

 更新時(shí)間:2019年02月11日 15:29:38   作者:邋遢的流浪劍客  
今天小編就為大家分享一篇關(guān)于JVM:晚期(運(yùn)行期)優(yōu)化的深入理解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧

晚期(運(yùn)行期)優(yōu)化

在部分的商用虛擬機(jī)中,Java程序最初是通過(guò)解釋器進(jìn)行解釋執(zhí)行的,當(dāng)虛擬機(jī)發(fā)現(xiàn)某個(gè)方法或代碼塊的運(yùn)行特別頻繁時(shí),就會(huì)把這些代碼認(rèn)定為熱點(diǎn)代碼。為了提高熱點(diǎn)代碼的執(zhí)行效率,在運(yùn)行時(shí),虛擬機(jī)會(huì)將這些代碼編譯成與本地平臺(tái)相關(guān)的機(jī)器碼,并進(jìn)行各種層次的優(yōu)化,完成這個(gè)任務(wù)的編譯器稱為即時(shí)編譯器

本章提到的編譯器、即時(shí)編譯器都是指HotSpot虛擬機(jī)內(nèi)的即時(shí)編譯器,虛擬機(jī)也是特質(zhì)HotSpot虛擬機(jī)

1、HotSpot虛擬機(jī)內(nèi)的即時(shí)編譯器

1)、解釋器與編譯器

當(dāng)程序需要迅速啟動(dòng)和執(zhí)行的時(shí)候,解釋器可以首先發(fā)揮作用,省去編譯的時(shí)間,立即執(zhí)行。在程序運(yùn)行后,隨著時(shí)間的推移,編譯器逐漸發(fā)揮作用,把越來(lái)越多的代碼編輯成本地代碼之后,可以獲取更高的執(zhí)行效率。當(dāng)程序運(yùn)行環(huán)境中內(nèi)存資源限制較大,可以使用解釋執(zhí)行節(jié)約內(nèi)存,反之可以使用編譯執(zhí)行來(lái)提升效率

HotSpot虛擬機(jī)中內(nèi)置了兩個(gè)即時(shí)編譯器,分別稱為Client Compiler和Server Compiler,或者簡(jiǎn)稱為C1編譯器和C2編譯器。目前主流的HotSpot虛擬機(jī)中,默認(rèn)采用解釋器與其中一個(gè)編譯器直接配合的方式工作,程序使用哪個(gè)編譯器,取決于虛擬機(jī)運(yùn)行的模式,HotSpot虛擬機(jī)會(huì)根據(jù)自身版本與宿主機(jī)器的硬件性能自動(dòng)選擇運(yùn)行模式。用戶也可以使用“-client”或“-server”參數(shù)去強(qiáng)制指定虛擬機(jī)運(yùn)行在Client模式或Server模式

解釋器與編譯器搭配使用的方式在虛擬機(jī)中稱為“混合模式”,用戶可以使用參數(shù)“-Xint”強(qiáng)制虛擬機(jī)運(yùn)行于解釋模式,這時(shí)編譯器完全不介入工作,全部代碼都使用解釋方式執(zhí)行。另外,也可以使用參數(shù)“-Xcomp”強(qiáng)制虛擬機(jī)運(yùn)行于編譯模式,這時(shí)將優(yōu)先采用編譯方式執(zhí)行程序,但是解釋器仍然要在編譯無(wú)法進(jìn)行的情況下介入執(zhí)行過(guò)程,可以通過(guò)虛擬機(jī)的“-version”命令的輸出結(jié)果顯示出這3中模式

C:\Users\hxt>java -version
java version "1.8.0_162"
Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode)
----------------------------------------------------------------------
C:\Users\hxt>java -Xint -version
java version "1.8.0_162"
Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, interpreted mode)
----------------------------------------------------------------------
C:\Users\hxt>java -Xcomp -version
java version "1.8.0_162"
Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, compiled mode)

為了在程序啟動(dòng)響應(yīng)速度與運(yùn)行效率之間達(dá)到最佳平衡,HotSpot虛擬機(jī)會(huì)啟用分層編譯的策略,分層編譯根據(jù)編譯器編譯、優(yōu)化的規(guī)模與耗時(shí),劃分出不同的編譯層次,其中包括:

  • 第0層,程序解釋執(zhí)行,解釋器不開(kāi)啟性能監(jiān)控功能,可觸發(fā)第1層編譯
  • 第1層,也稱為C1編譯,將字節(jié)碼編譯為本地代碼,進(jìn)行簡(jiǎn)單、可靠的優(yōu)化,如有必要將加入性能監(jiān)控的邏輯
  • 第2層,也稱為C2編譯,也是將字節(jié)碼編譯為本地代碼,但是會(huì)啟用一些編譯耗時(shí)較長(zhǎng)的優(yōu)化,甚至?xí)鶕?jù)性能監(jiān)控信息進(jìn)行一些不可靠的激進(jìn)優(yōu)化

用C1編譯器獲取更高的編譯速度,用C2編譯器獲取更高的編譯質(zhì)量,在解釋執(zhí)行的時(shí)候也無(wú)須再承擔(dān)收集性能監(jiān)控信息的任務(wù)

2)、編譯對(duì)象與觸發(fā)條件

在運(yùn)行過(guò)程中會(huì)被即時(shí)編譯器編譯的熱點(diǎn)代碼有兩類:

  • 被多次調(diào)用的方法
  • 被多次執(zhí)行的循環(huán)體

對(duì)于第一種情況,由于是由方法調(diào)用觸發(fā)的編譯,因此編譯器會(huì)以整個(gè)方法作為編譯對(duì)象,這種編譯也是虛擬機(jī)標(biāo)準(zhǔn)的JIT編譯方式。而對(duì)于后一種情況,盡管編譯動(dòng)作是由循環(huán)體所觸發(fā)的,但編譯器依然會(huì)以整個(gè)方法作為編譯對(duì)象。這種編譯方式因?yàn)榫幾g發(fā)生在方法執(zhí)行過(guò)程之中,因此稱之為棧上替換(OSR編譯,即方法幀還在棧上,方法就被替換了)

判斷一段代碼是不是熱點(diǎn)代碼,是不是需要觸發(fā)即時(shí)編譯,這樣的行為稱為熱點(diǎn)探測(cè),其實(shí)進(jìn)行熱點(diǎn)探測(cè)并不一定要知道方法具體被調(diào)用了多少次,目前主要的熱點(diǎn)探測(cè)判定方式有兩種:

  • 基于采用的熱點(diǎn)探測(cè):采用這種方式的虛擬機(jī)會(huì)周期性地檢查各個(gè)線程的棧頂,如果發(fā)現(xiàn)某個(gè)方法經(jīng)常出現(xiàn)在棧頂,那這個(gè)方法就是熱點(diǎn)方法?;诓蓸拥臒狳c(diǎn)探測(cè)的好處是實(shí)現(xiàn)簡(jiǎn)單、高效,還可以很容易地獲取方法調(diào)用關(guān)系,缺點(diǎn)是很難精確地確認(rèn)一個(gè)方法的熱度,容易因?yàn)槭艿骄€程阻塞或別的外界因素的影響而擾亂熱點(diǎn)探測(cè)
  • 基于計(jì)數(shù)器的熱點(diǎn)探測(cè):采用這種方法的虛擬機(jī)會(huì)為每個(gè)方法建立計(jì)數(shù)器,統(tǒng)計(jì)方法的執(zhí)行次數(shù),如果執(zhí)行次數(shù)超過(guò)一定的閾值就認(rèn)為它是熱點(diǎn)方法。這種統(tǒng)計(jì)方法實(shí)現(xiàn)起來(lái)麻煩一些,需要為每個(gè)方法建立并維護(hù)計(jì)數(shù)器,而且不能直接獲取到方法的調(diào)用關(guān)系,但是它的統(tǒng)計(jì)結(jié)果相對(duì)來(lái)說(shuō)更加精確和嚴(yán)謹(jǐn)

在HotSpot虛擬機(jī)中使用的是基于計(jì)數(shù)器的熱點(diǎn)探測(cè),因此它為每個(gè)方法準(zhǔn)備了兩類計(jì)數(shù)器:方法調(diào)用計(jì)數(shù)器和回邊計(jì)數(shù)器

在確定虛擬機(jī)運(yùn)行參數(shù)的前提下,這兩個(gè)計(jì)數(shù)器都有一個(gè)確定的閾值,當(dāng)計(jì)數(shù)器超過(guò)閾值溢出了,就會(huì)觸發(fā)JIT編譯

方法調(diào)用計(jì)數(shù)器用于統(tǒng)計(jì)方法被調(diào)用的次數(shù),它的默認(rèn)閾值在Client模式下是1500次,在Server模式下是10000 次,這個(gè)閾值可以通過(guò)虛擬機(jī)參數(shù)-XX:CompileThreshold來(lái)設(shè)定。當(dāng)一個(gè)方法被調(diào)用時(shí),會(huì)先檢查該方法是否存在被JIT編譯過(guò)的版本,如果存在,則優(yōu)先使用編譯后的本地代碼來(lái)執(zhí)行。如果不存在已被編譯過(guò)的版本,則將此方法的調(diào)用計(jì)數(shù)器值加1,然后判斷方法調(diào)用計(jì)數(shù)器與回邊計(jì)數(shù)器值之和是否查過(guò)方法調(diào)用計(jì)數(shù)器的閾值。如果已超過(guò)閾值,那么將會(huì)向即時(shí)編譯器提交一個(gè)該方法的代碼編譯請(qǐng)求

如果不做任何設(shè)置,方法調(diào)用計(jì)數(shù)器統(tǒng)計(jì)的并不是方法被調(diào)用的絕對(duì)次數(shù),而是一個(gè)相對(duì)的執(zhí)行頻率,即一段時(shí)間之內(nèi)方法被調(diào)用的次數(shù)。當(dāng)超過(guò)一定的時(shí)間限度,如果方法的調(diào)用次數(shù)仍然不足以讓它提交給即時(shí)編譯器編譯,那這個(gè)方法的調(diào)用計(jì)數(shù)器就會(huì)被減少一半,這個(gè)過(guò)程稱為方法調(diào)用計(jì)數(shù)器熱度的衰減,而這段時(shí)間就稱為此方法統(tǒng)計(jì)的半衰周期。進(jìn)行熱度衰減的動(dòng)作是在虛擬機(jī)進(jìn)行垃圾收集時(shí)順便進(jìn)行的,可以使用虛擬機(jī)參數(shù)-XX: -UseCounterDecay來(lái)關(guān)閉熱度衰減,讓方法計(jì)數(shù)器統(tǒng)計(jì)方法調(diào)用的絕對(duì)次數(shù),這樣,只要系統(tǒng)運(yùn)行時(shí)間足夠長(zhǎng),絕大部分方法都會(huì)被編譯成本地代碼。另外,可以使用-XX:CounterHalfLifeTime參數(shù)設(shè)置半衰周期的時(shí)間,單位是秒

回邊計(jì)數(shù)器,它的作用是統(tǒng)計(jì)一個(gè)方法中循環(huán)體代碼執(zhí)行的次數(shù),在字節(jié)碼中遇到控制流向后跳轉(zhuǎn)的指令稱為 “回邊”。顯然,建立回邊計(jì)數(shù)器統(tǒng)計(jì)的目的就是為了觸發(fā)OSR編譯

關(guān)于回邊計(jì)數(shù)器的閾值,雖然HotSpot虛擬機(jī)也提供了一個(gè)類似于方法調(diào)用計(jì)數(shù)器閾值-XX:CompileThreshold的參數(shù)-XX:BackEdgeThreashold供用戶設(shè)置,但是當(dāng)前的虛擬機(jī)實(shí)際上并未使用此參數(shù),因此我們需要設(shè)置另外一個(gè)參數(shù)-XX:OnStackReplacePercentage來(lái)簡(jiǎn)介調(diào)整回邊計(jì)數(shù)器的閾值,其計(jì)算公式如下

  • 虛擬機(jī)運(yùn)行在 Client 模式下,回邊計(jì)數(shù)器閾值計(jì)算公式為:

方法調(diào)用計(jì)數(shù)器閾值(CompileThreshold)× OSR 比率(OnStackReplacePercentage)/ 100

其中OnStackReplacePercentage默認(rèn)值為933,如果都取默認(rèn)值,那Client模式虛擬機(jī)的回邊計(jì)數(shù)器的閾值為 13995

  • 虛擬機(jī)運(yùn)行在 Server 模式下,回邊計(jì)數(shù)器閾值的計(jì)算公式為:

方法調(diào)用計(jì)數(shù)器閾值(CompileThreshold)× (OSR 比率(OnStackReplacePercentage)- 解釋器監(jiān)控比率(InterpreterProfilePercentage)) / 100

?其中OnStackReplacePercentage默認(rèn)值為140,InterpreterProfilePercentage默認(rèn)值為33,如果都取默認(rèn)值,那Server模式虛擬機(jī)回邊計(jì)數(shù)器的閾值為10700

當(dāng)解釋器遇到一條回邊指令時(shí),會(huì)先查找將要執(zhí)行的代碼片段是否有已經(jīng)編譯好的版本,如果有,它將會(huì)有限執(zhí)行已編譯的代碼,否則就把回邊計(jì)數(shù)器的值加 1,然后判斷方法調(diào)用計(jì)數(shù)器與回邊計(jì)數(shù)器之和是否超過(guò)回邊計(jì)數(shù)器的閾值。當(dāng)超過(guò)閾值的時(shí)候,將會(huì)提交一個(gè)OSR編譯請(qǐng)求,并且把回邊計(jì)數(shù)器的值降低一些,以便繼續(xù)在解釋器中執(zhí)行循環(huán),等待編譯器輸出編譯結(jié)果

與方法計(jì)數(shù)器不同,回邊計(jì)數(shù)器沒(méi)有計(jì)數(shù)熱度衰減的過(guò)程,因此這個(gè)計(jì)數(shù)器統(tǒng)計(jì)的就是該方法循環(huán)執(zhí)行的絕對(duì)次數(shù)。當(dāng)計(jì)數(shù)器溢出的時(shí)候,它還會(huì)把方法計(jì)數(shù)器的值也調(diào)整到溢出狀態(tài),這樣下次再進(jìn)入該方法的時(shí)候就會(huì)執(zhí)行標(biāo)準(zhǔn)編譯過(guò)程

上述內(nèi)容僅僅描述了Client VM的即時(shí)編譯方式,對(duì)于Server VM來(lái)說(shuō),執(zhí)行情況會(huì)比上面的描述更復(fù)雜一些

3)、編譯過(guò)程

在默認(rèn)設(shè)置下,無(wú)論是方法調(diào)用產(chǎn)生的即時(shí)編譯請(qǐng)求,還是OSR編譯請(qǐng)求,虛擬機(jī)在代碼編譯器還未完成之前,都仍然將按照解釋方式繼續(xù)執(zhí)行,而編譯動(dòng)作則在后臺(tái)的編譯線程中進(jìn)行。用戶可以通過(guò)參數(shù)-XX: -BackgroundCompilation來(lái)禁止后臺(tái)編譯,在禁止后臺(tái)編譯后,一旦達(dá)到JIT的編譯條件,執(zhí)行線程向虛擬機(jī)提交編譯請(qǐng)求后將會(huì)一直等待,直到編譯過(guò)程完成后再開(kāi)始執(zhí)行編譯器輸出的本地代碼

對(duì)于Client Compiler來(lái)說(shuō),它是一個(gè)簡(jiǎn)單快速的三段式編譯器,主要的關(guān)注點(diǎn)在于局部性的優(yōu)化,而放棄了許多耗時(shí)較長(zhǎng)的全局優(yōu)化手段

在第一個(gè)階段,一個(gè)平臺(tái)的前端將字節(jié)碼構(gòu)造成一種高級(jí)中間代碼表示(HIR)。HIR使用靜態(tài)單分配的形式代表代碼值,這可以使得一些在HIR的構(gòu)造過(guò)程之中和之后進(jìn)行的優(yōu)化動(dòng)作更容易實(shí)現(xiàn)。在此之前編譯器會(huì)在字節(jié)碼上完成一部分基礎(chǔ)優(yōu)化,如方法內(nèi)聯(lián)、常量傳播等優(yōu)化將會(huì)在字節(jié)碼被構(gòu)造成 HIR之前完成。

在第二個(gè)階段,一個(gè)平臺(tái)相關(guān)的后端從HIR中產(chǎn)生低級(jí)中間代碼表示(LIR),而在此之前會(huì)在HIR上完成另外一些優(yōu)化,如空值檢查消除、范圍檢查消除等,以便讓HIR達(dá)到更高效的代碼表示形式。

最后階段是在平臺(tái)相關(guān)的后端使用線性掃描算法在LIR上分配寄存器,并在LIR上做窺孔優(yōu)化,然后產(chǎn)生機(jī)器代碼

Server Compiler是專門(mén)面向服務(wù)端的典型應(yīng)用并為服務(wù)端的性能配置特別調(diào)整過(guò)的編譯器,也是一個(gè)充分優(yōu)化過(guò)的高級(jí)編譯器,還可以根據(jù)解釋器或Client Compiler提供的性能監(jiān)控信息,進(jìn)行一些不穩(wěn)定的激進(jìn)優(yōu)化

Server Compiler的寄存器分配器是一個(gè)全局圖著色分配器,它可以充分利用某些處理器架構(gòu)上的大寄存器集合

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

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

如果一個(gè)表達(dá)式E已經(jīng)計(jì)算過(guò)了,并且從先前的計(jì)算到現(xiàn)在E中所有變量的值都沒(méi)有發(fā)生變化,那么E的這次出現(xiàn)就成為了公共子表達(dá)式。對(duì)于這種表達(dá)式,沒(méi)有必要花時(shí)間在對(duì)它進(jìn)行計(jì)算,只需要直接用前面計(jì)算過(guò)的表達(dá)式結(jié)果代替E就可以了。如果這種優(yōu)化僅限于程序的基本塊內(nèi),便稱為局部公共子表達(dá)式消除,如果這種優(yōu)化的范圍涵蓋了多個(gè)基本塊,那就稱為全局公共子表達(dá)式消除

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

Java語(yǔ)言是一門(mén)動(dòng)態(tài)安全的語(yǔ)言,數(shù)組邊界檢查是必須做的,但數(shù)組邊界檢查是不是必須在運(yùn)行期間一次不漏地檢查則是可以商量的事情。比如,數(shù)組下標(biāo)是一個(gè)常量,如foo[3],只要在編譯期根據(jù)數(shù)據(jù)流分析來(lái)確定foo.length的值,并判斷下標(biāo)3沒(méi)有越界,執(zhí)行的時(shí)候就無(wú)須判斷了。數(shù)組訪問(wèn)發(fā)生在循環(huán)之中,并且使用循環(huán)變量來(lái)進(jìn)行數(shù)組訪問(wèn),如果編譯器只要通過(guò)數(shù)據(jù)流分析就可以判定循環(huán)變量的取值范圍永遠(yuǎn)在區(qū)間[0,foo.length)之內(nèi),那在整個(gè)循環(huán)中就可以把數(shù)組的上下界檢查消除,這可以節(jié)省很多次的條件判斷操作

隱式異常處理:Java中空指針檢查和算數(shù)運(yùn)算中除數(shù)為零的檢查都采用了隱式異常處理

if (foo != null) {
  return foo.value;
else {
  throw new NullPointException();
}

在使用隱式異常優(yōu)化之后,虛擬機(jī)會(huì)把上面?zhèn)未a所表示的訪問(wèn)過(guò)程變?yōu)槿缦聜未a

try {
   return foo.value;
} catch (segment_fault) {
  uncommon_trap();
}

虛擬機(jī)會(huì)注冊(cè)一個(gè)Segment Fault信號(hào)的異常處理器(偽代碼中的uncommon_trap()),這樣當(dāng)foo不為空的Z候,對(duì)value的訪問(wèn)是不會(huì)額外消耗一次對(duì)foo判空的開(kāi)銷(xiāo)的。代價(jià)就是當(dāng)foo真的為空時(shí),必須轉(zhuǎn)入到異常處理器中恢復(fù)并拋出NullPointException異常,這個(gè)過(guò)程必須從用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài)中處理,結(jié)束后再回到用戶態(tài),速度遠(yuǎn)比一次判空檢查慢。當(dāng)foo極少為空的時(shí)候,隱式異常優(yōu)化是值得的,但假如foo經(jīng)常為空的話,這樣的優(yōu)化反而會(huì)讓程序更慢,還好HotSpot虛擬機(jī)會(huì)根據(jù)運(yùn)行期收集到的 Profile 信息自動(dòng)選擇最優(yōu)方案

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

方法內(nèi)聯(lián)除了消除方法調(diào)用的成本之外,還為其他優(yōu)化手段建立良好的基礎(chǔ)

只有使用invokespecial指令調(diào)用的私有方法、實(shí)例構(gòu)造器、父類方法以及使用invokestatic指令進(jìn)行調(diào)用的靜態(tài)方法才是在編譯期進(jìn)行解析的,除了上述4中方法之外,其他的Java方法調(diào)用都需要在運(yùn)行時(shí)進(jìn)行方法接收者的多態(tài)選擇,并且都有可能存在多于一個(gè)版本的方法接收者,Java語(yǔ)言中默認(rèn)的實(shí)例方法是虛方法

對(duì)于一個(gè)虛方法,編譯器做內(nèi)聯(lián)的時(shí)候根本無(wú)法確定應(yīng)該使用哪個(gè)版本,為了解決虛方法的內(nèi)聯(lián)問(wèn)題,引入了一種名為類型繼承關(guān)系分析(CHA)的技術(shù),這是一種基于整個(gè)應(yīng)用程序的類型分析技術(shù),它用于確定在目前已加載的類中,某個(gè)接口是否有多于一種的實(shí)現(xiàn),某個(gè)類是否存在子類、子類是否為抽象類等信息

編譯器在進(jìn)行內(nèi)聯(lián)時(shí),如果是非虛方法,那么直接進(jìn)行內(nèi)聯(lián)就可以了,這時(shí)候的內(nèi)聯(lián)是有穩(wěn)定前提保障的。如果遇到虛方法,則會(huì)向CHA查詢方法在當(dāng)前程序下是否有多個(gè)目標(biāo)版本可供選擇,如果查詢結(jié)果只有一個(gè)版本,那也可以進(jìn)行內(nèi)聯(lián),不過(guò)這種內(nèi)聯(lián)就屬于激進(jìn)優(yōu)化,需要預(yù)留一個(gè)逃生門(mén)稱為守護(hù)內(nèi)聯(lián)。如果程序的后續(xù)執(zhí)行過(guò)程中,虛擬機(jī)一直沒(méi)有加載到會(huì)令這個(gè)方法的接收者的繼承關(guān)系發(fā)生變化的類,那這個(gè)內(nèi)聯(lián)優(yōu)化的代碼就可以一直使用下去。但如果加載了導(dǎo)致繼承關(guān)系發(fā)生變化的新類,那就需要拋棄已經(jīng)編譯的代碼,退回到解釋狀態(tài)執(zhí)行,或者重新進(jìn)行編譯

如果向CHA查詢出來(lái)的結(jié)果是有多個(gè)版本的目標(biāo)方法可供選擇,編譯器使用內(nèi)聯(lián)緩存來(lái)完成方法內(nèi)聯(lián),在未發(fā)生方法調(diào)用之前,內(nèi)聯(lián)緩存狀態(tài)為空,當(dāng)?shù)谝淮握{(diào)用發(fā)生后,緩存記錄下方法接收者的版本信息,并且每次進(jìn)行方法調(diào)用時(shí)都比較接收者版本,如果以后進(jìn)來(lái)的每次調(diào)用的方法接收者版本都是一樣的,那這個(gè)內(nèi)聯(lián)還可以一直用下去。如果發(fā)生了方法接收者不一致的情況,就說(shuō)明程序真正使用了虛方法的多態(tài)特性,這時(shí)才會(huì)取消內(nèi)聯(lián),查找虛方法表進(jìn)行方法分派

4)、逃逸分析

逃逸分析是為其他優(yōu)化手段提供依據(jù)的分析技術(shù)

逃逸分析的基本行為就是分析對(duì)象動(dòng)態(tài)作用域:當(dāng)一個(gè)對(duì)象在方法中被定義后,它可能被外部方法所引用,例如作為調(diào)用參數(shù)傳遞到其他方法中,稱為方法逃逸。甚至還有可能被外部線程訪問(wèn)到,譬如賦值給類變量或可以在其他線程中訪問(wèn)的實(shí)例變量,稱為線程逃逸

如果能證明一個(gè)對(duì)象不會(huì)逃逸到方法或線程之外,也就是別的方法或線程無(wú)法通過(guò)任何途徑訪問(wèn)到這個(gè)對(duì)象,則可能為這個(gè)變量進(jìn)行一些高效的優(yōu)化:

  • 棧上分配:如果確定一個(gè)對(duì)象不會(huì)逃逸出方法之外,那讓這個(gè)對(duì)象在棧上分配內(nèi)存將會(huì)是一個(gè)很不錯(cuò)的主意,對(duì)象所占用的空間內(nèi)存就可以隨棧幀出棧而銷(xiāo)毀。在一般應(yīng)用中,不會(huì)逃逸的局部對(duì)象所占的比例很大,如果能使用棧上分配,那大量的對(duì)象就會(huì)隨著方法的結(jié)束而自動(dòng)銷(xiāo)毀了,垃圾收集系統(tǒng)的壓力將會(huì)小很多
  • 同步消除:線程同步本身是一個(gè)相對(duì)耗時(shí)的過(guò)程,如果逃逸分析能夠確定一個(gè)變量不會(huì)逃逸出線程,無(wú)法被其他線程訪問(wèn),那這個(gè)變量的讀寫(xiě)肯定就不會(huì)有競(jìng)爭(zhēng),對(duì)這個(gè)變量實(shí)施的同步措施也就可以消除掉
  • 標(biāo)量替換:標(biāo)量是指一個(gè)數(shù)據(jù)已經(jīng)無(wú)法再分解成更小的數(shù)據(jù)來(lái)表示了,Java虛擬機(jī)中的原始數(shù)據(jù)類型(int、long等數(shù)值類型以及reference類型等)都不能再進(jìn)一步分解,它們就可以稱為標(biāo)量。相對(duì)的,如果一個(gè)數(shù)據(jù)可以繼續(xù)分解,那它就稱作聚合量,Java中的對(duì)象就是最典型的聚合量。如果把一個(gè)Java對(duì)象拆散,根據(jù)程序訪問(wèn)的情況,將其使用到的成員變量恢復(fù)原始類型來(lái)訪問(wèn)就叫做標(biāo)量替換。如果逃逸分析證明一個(gè)對(duì)象不會(huì)被外部訪問(wèn),并且這個(gè)對(duì)象可以被拆散的話,那程序真正執(zhí)行的時(shí)候?qū)⒖赡懿粍?chuàng)建這個(gè)對(duì)象,而改為直接創(chuàng)建它的若干個(gè)被這個(gè)方法使用的成員變量來(lái)代替。將對(duì)象拆分后,除了可以讓對(duì)象的成員變量在棧上分配和讀寫(xiě)外,還可以為后續(xù)進(jìn)一步的優(yōu)化手段創(chuàng)建條件

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接

相關(guān)文章

最新評(píng)論