真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

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

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

創(chuàng)新互聯(lián)公司網(wǎng)站建設(shè)公司,提供成都網(wǎng)站設(shè)計、網(wǎng)站制作,網(wǎng)頁設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);可快速的進行網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,是專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!

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

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

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

1)、解釋器與編譯器

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

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

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

解釋器與編譯器搭配使用的方式在虛擬機中稱為“混合模式”,用戶可以使用參數(shù)“-Xint”強制虛擬機運行于解釋模式,這時編譯器完全不介入工作,全部代碼都使用解釋方式執(zhí)行。另外,也可以使用參數(shù)“-Xcomp”強制虛擬機運行于編譯模式,這時將優(yōu)先采用編譯方式執(zhí)行程序,但是解釋器仍然要在編譯無法進行的情況下介入執(zhí)行過程,可以通過虛擬機的“-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)

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

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

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

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

在運行過程中會被即時編譯器編譯的熱點代碼有兩類:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3)、編譯過程

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

對于Client Compiler來說,它是一個簡單快速的三段式編譯器,主要的關(guān)注點在于局部性的優(yōu)化,而放棄了許多耗時較長的全局優(yōu)化手段

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

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

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

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

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

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

1)、公共子表達式消除

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4)、逃逸分析

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

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

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

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

總結(jié)

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


本文標(biāo)題:JVM:晚期(運行期)優(yōu)化的深入理解
網(wǎng)站網(wǎng)址:http://weahome.cn/article/jesppe.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部