摘要:解釋器與編譯器并存如果選用完全解釋策略,那么編譯器將停止所有的工作,字節(jié)碼將完全依靠解釋器逐行解釋執(zhí)行。如果選用完全編譯策略,那么解釋器仍然會(huì)在編譯器無法進(jìn)行的特殊情況下介入運(yùn)行,這主要是確保程序能夠最終順序執(zhí)行。
jvm系列
垃圾回收基礎(chǔ)
JVM的編譯策略
GC的三大基礎(chǔ)算法
GC的三大高級(jí)算法
GC策略的評(píng)價(jià)指標(biāo)
JVM信息查看
GC通用日志解讀
jvm的card table數(shù)據(jù)結(jié)構(gòu)
Java類初始化順序
Java對(duì)象結(jié)構(gòu)及大小計(jì)算
Java的類加載機(jī)制
Java對(duì)象分配簡(jiǎn)要流程
年老代過大有什么影響
Survivor空間溢出實(shí)例
關(guān)于Object=null
Java線程與Xss
序本文主要講述JVM的編譯策略。
解釋器當(dāng)虛擬機(jī)啟動(dòng)時(shí),解釋器可以首先發(fā)揮作用,而不必等待編譯器全部編譯完成再執(zhí)行,這樣可以省去許多不必要的編譯時(shí)間。并且隨著程序運(yùn)行時(shí)間的推移,編譯器逐漸發(fā)揮作用,根據(jù)熱點(diǎn)探測(cè)功能,,將有價(jià)值的字節(jié)碼編譯為本地機(jī)器指令,以換取更高的程序執(zhí)行效率。
C1編譯器hotspot中內(nèi)嵌有2個(gè)JIT編譯器,分別為Client Compiler,Server Compiler,但大多數(shù)情況下我們稱之為C1編譯器和C2編譯器。
client compiler,又稱C1編譯器,較為輕量,只做少量性能開銷比較高的優(yōu)化,它占用內(nèi)存較少,適合于桌面交互式應(yīng)用。在寄存器分配策略上,JDK6以后采用的為線性掃描寄存器分配算法,其他方面的優(yōu)化,主要有方法內(nèi)聯(lián)、去虛擬化、冗余消除等。
A、方法內(nèi)聯(lián)多個(gè)方法調(diào)用,執(zhí)行時(shí)要經(jīng)歷多次參數(shù)傳遞,返回值傳遞及跳轉(zhuǎn)等,C1采用方法內(nèi)聯(lián),把調(diào)用到的方法的指令直接植入當(dāng)前方法中。-XX:+PringInlining來查看方法內(nèi)聯(lián)信息,-XX:MaxInlineSize=35控制編譯后文件大小。
B、去虛擬化是指在裝載class文件后,進(jìn)行類層次的分析,如果發(fā)現(xiàn)類中的方法只提供一個(gè)實(shí)現(xiàn)類,那么對(duì)于調(diào)用了此方法的代碼,也可以進(jìn)行方法內(nèi)聯(lián),從而提升執(zhí)行的性能。
C、冗余消除在編譯時(shí)根據(jù)運(yùn)行時(shí)狀況進(jìn)行代碼折疊或消除。
C2編譯器Server compiler,稱為C2編譯器,較為重量,采用了大量傳統(tǒng)編譯優(yōu)化的技巧來進(jìn)行優(yōu)化,占用內(nèi)存相對(duì)多一些,適合服務(wù)器端的應(yīng)用。和C1的不同主要在于寄存器分配策略及優(yōu)化范圍,寄存器分配策略上C2采用的為傳統(tǒng)的圖著色寄存器分配算法,由于C2會(huì)收集程序運(yùn)行信息,因此其優(yōu)化范圍更多在于全局優(yōu)化,不僅僅是一個(gè)方塊的優(yōu)化。收集的信息主要有:分支的跳轉(zhuǎn)/不跳轉(zhuǎn)的頻率、某條指令上出現(xiàn)過的類型、是否出現(xiàn)過空值、是否出現(xiàn)過異常等。
逃逸分析是C2進(jìn)行很多優(yōu)化的基礎(chǔ),它根據(jù)運(yùn)行狀態(tài)來判斷方法中的變量是否會(huì)被外部讀取,如不會(huì)則認(rèn)為此變量是不會(huì)逃逸的,那么在編譯時(shí)會(huì)做標(biāo)量替換、棧上分配和同步消除等優(yōu)化。
(1)標(biāo)量替換簡(jiǎn)單地說,就是用標(biāo)量替換聚合量。這樣做的好處是如果創(chuàng)建的對(duì)象并未用到其中的全部變量,則可以節(jié)省一定的內(nèi)存。對(duì)于代碼執(zhí)行而言,無需去找對(duì)象的引用,也會(huì)更快一些。
(2)棧上分配如果point沒有逃逸,那么C2會(huì)選擇在棧上直接創(chuàng)建Point對(duì)象的實(shí)例,而不是在JVM堆上。在棧上分配的好處一方面是加快速度,另一方面是回收時(shí)隨著方法的結(jié)束,對(duì)象被回收了。
(3)同步消除如果發(fā)現(xiàn)同步的對(duì)象未逃逸,那也就沒有必要進(jìn)行同步了,C2編譯時(shí)會(huì)直接去掉同步。
C2還會(huì)基于擁有的運(yùn)行信息來做其他優(yōu)化,比如編譯分支頻率執(zhí)行高的代碼等。
運(yùn)行后C1、C2編譯出來的機(jī)器碼如果不再符合優(yōu)化條件,則會(huì)進(jìn)行逆優(yōu)化,也就是回到解釋執(zhí)行的方式,例如基于類層次分析編譯的代碼,當(dāng)有新的相應(yīng)的接口來實(shí)現(xiàn)類加入時(shí),就執(zhí)行逆優(yōu)化。
OSR編譯除了C1、C2外,還有OSR(On Stack Replace)編譯,只替換循環(huán)代碼體的入口,C1、C2替換的是方法調(diào)用的入口。因此OSR編譯后會(huì)出現(xiàn)的現(xiàn)象是方法的整段代碼被編譯了,但是只有循環(huán)體部分才執(zhí)行編譯后的機(jī)器碼,其他部分仍是解釋執(zhí)行。
當(dāng)機(jī)器配置CPU超過2核且內(nèi)存超過2G,默認(rèn)為server模式,32位的windows始終選擇的是client模式。
分層編譯Java7默認(rèn)開啟分層編譯(tiered compilation)策略,由C1編譯器和C2編譯器相互協(xié)作共同來執(zhí)行編譯任務(wù)。C1編譯器會(huì)對(duì)字節(jié)碼進(jìn)行簡(jiǎn)單和可靠的優(yōu)化,以達(dá)到更快的編譯速度;C2編譯器會(huì)啟動(dòng)一些編譯耗時(shí)更長(zhǎng)的優(yōu)化,以獲取更好的編譯質(zhì)量。
(1)解釋器不再收集運(yùn)行狀態(tài)信息,只用于啟動(dòng)并觸發(fā)C1編譯
(2)C1編譯后生成帶收集運(yùn)行信息的代碼
(3)C2編譯,基于C1編譯后代碼收集的運(yùn)行信息進(jìn)行激進(jìn)優(yōu)化,當(dāng)激進(jìn)優(yōu)化的假設(shè)不成立時(shí),再退回使用C1編譯的代碼
程序在未編譯期間解釋執(zhí)行有個(gè)閾值,SunJDK主要依據(jù)方法上的兩個(gè)計(jì)數(shù)器是否超過閾值來判斷:
A、調(diào)用計(jì)數(shù)器,即方法被調(diào)用的次數(shù),CompileThreshold,該值是指當(dāng)方法被調(diào)用多少次后,就編譯為機(jī)器碼,client模式默認(rèn)為1500次,server模式默認(rèn)為1萬次,可以在啟動(dòng)時(shí)添加-XX:CompileThreshold=10000來設(shè)置該值。
B、回邊計(jì)數(shù)器,即方法中循環(huán)執(zhí)行部分代碼的執(zhí)行次數(shù),OnStackReplacePercentage,該值用于/參與計(jì)算是否觸發(fā)OSR編譯的閾值,client默認(rèn)為933,sever默認(rèn)為140,可以通過-XX: OnStackReplacePercentage=140來設(shè)置。
client模式下的計(jì)算規(guī)則為CompileThreshold*OnStackReplacePercentage/100,
server模式下計(jì)算規(guī)則為CompileThreshold*(OnStackReplacePercentage-InterpreterProfilePercentage)/100。InterpreterProfilePercentage,默認(rèn)為33。
當(dāng)方法上的回邊計(jì)數(shù)器到達(dá)這個(gè)值時(shí),觸發(fā)后臺(tái)的OSR編譯,并將方法上累積的調(diào)用計(jì)數(shù)器設(shè)置為CompileThreshold 的值,同時(shí)將回邊計(jì)數(shù)器設(shè)置為CompileThreshold/2的值。這樣做一方面是為了避免OSR編譯頻繁被觸發(fā),另一方面是以便當(dāng)方法被再次調(diào)用時(shí)即觸發(fā)正常的編譯,當(dāng)累積的回邊計(jì)數(shù)器的值再次達(dá)到該值時(shí)先檢查OSR編譯是否完成,如果已完成,則在執(zhí)行循環(huán)體的代碼時(shí)進(jìn)入編譯后的代碼,如果未完成,繼續(xù)把當(dāng)前回邊計(jì)數(shù)器的累計(jì)值再減掉一些,默認(rèn)情況下,對(duì)于回邊的情況,server模式下只要回邊次數(shù)達(dá)到10700次(10000*(140-33)),就會(huì)觸發(fā)OSR編譯。
解釋器與編譯器并存如果選用完全解釋策略,那么編譯器將停止所有的工作,字節(jié)碼將完全依靠解釋器逐行解釋執(zhí)行。
如果選用完全編譯策略,那么解釋器仍然會(huì)在編譯器無法進(jìn)行的特殊情況下介入運(yùn)行,這主要是確保程序能夠最終順序執(zhí)行。
SunJDK之所以未選擇在啟動(dòng)時(shí)即編譯成機(jī)器碼的原因如下:
(1)靜態(tài)編譯并不能根據(jù)程序的運(yùn)行狀態(tài)來優(yōu)化執(zhí)行的代碼,C2這種方式是根據(jù)運(yùn)行狀態(tài)來進(jìn)行動(dòng)態(tài)編譯的,例如分支判斷、逃逸分析等,這些措施會(huì)對(duì)提升程序執(zhí)行的性能起到很大的幫助,在靜態(tài)編譯的情況下是無法實(shí)現(xiàn)的,給C2收集運(yùn)行數(shù)據(jù)越長(zhǎng)的時(shí)間,編譯出來的代碼會(huì)越優(yōu)。
(2)解釋執(zhí)行比編譯執(zhí)行更節(jié)省內(nèi)存
(3)啟動(dòng)時(shí)解釋執(zhí)行的啟動(dòng)速度比編譯再啟動(dòng)更快。
深入理解Java虛擬機(jī)(第2版)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/65645.html
摘要:周四正式發(fā)布了編程語言,將靜態(tài)類型以及一些現(xiàn)代的語言特性引入了。這是對(duì)優(yōu)化之路上的新里程碑。但是語言層面的優(yōu)化限制太多,對(duì)而言還是不夠用。其次是優(yōu)化運(yùn)行的步驟。在這方面進(jìn)行調(diào)整,可以提升運(yùn)行的性能。值得注意的是,給的影響很大。 Facebook周四正式發(fā)布了Hack編程語言,將靜態(tài)類型以及一些現(xiàn)代的語言特性引入了PHP。這是Facebook對(duì)PHP優(yōu)化之路上的新里程碑。 showIm...
摘要:被多次執(zhí)行的循環(huán)體。數(shù)組范圍檢查消除。這種安全檢查策略可以避免溢出。不過,虛擬機(jī)還是挺聰明的,它會(huì)根據(jù)運(yùn)行期收集到的信息來自動(dòng)選擇最優(yōu)方案。 1.解釋器與JIT編譯器 首先我們先來了解一下運(yùn)行在虛擬機(jī)之上的解釋器與JIT編譯器。 當(dāng)我們的虛擬機(jī)在運(yùn)行一個(gè)java程序的時(shí)候,它可以采用兩種方式來運(yùn)行這個(gè)java程序: 采用解釋器的形式,也就是說,在運(yùn)行.class運(yùn)行的時(shí)候,解釋器一邊...
摘要:對(duì)字節(jié)碼文件進(jìn)行解釋執(zhí)行,把字節(jié)碼翻譯成相關(guān)平臺(tái)上的機(jī)器指令。使用命令可對(duì)字節(jié)碼文件以及配置文件進(jìn)行打包可對(duì)一個(gè)由多個(gè)字節(jié)碼文件和配置文件等資源文件構(gòu)成的項(xiàng)目進(jìn)行打包。和不存在永久代這種說法。 Java技術(shù)體系 從廣義上講,Clojure、JRuby、Groovy等運(yùn)行于Java虛擬機(jī)上的語言及其相關(guān)的程序都屬于Java技術(shù)體系中的一員。如果僅從傳統(tǒng)意義上來看,Sun官方所定義的Jav...
摘要:概要要理解的內(nèi)存管理策略,首先就要熟悉的運(yùn)行時(shí)數(shù)據(jù)區(qū),如上圖所示,在執(zhí)行程序的時(shí)候,虛擬機(jī)會(huì)把它所管理的內(nèi)存劃分為多個(gè)不同的數(shù)據(jù)區(qū),稱為運(yùn)行時(shí)數(shù)據(jù)區(qū)。 這是一篇有關(guān)JVM內(nèi)存管理的文章。這里將會(huì)簡(jiǎn)單的分析一下Java如何使用從物理內(nèi)存上申請(qǐng)下來的內(nèi)存,以及如何來劃分它們,后面還會(huì)介紹JVM的核心技術(shù):如何分配和回收內(nèi)存。 JMM ( Java Memory Model )概要 show...
學(xué)習(xí)JVM的相關(guān)資料 《深入理解Java虛擬機(jī)——JVM高級(jí)特性與最佳實(shí)踐(第2版)》 showImg(https://segmentfault.com/img/bVbsqF5?w=200&h=200); 基于最新JDK1.7,圍繞內(nèi)存管理、執(zhí)行子系統(tǒng)、程序編譯與優(yōu)化、高效并發(fā)等核心主題對(duì)JVM進(jìn)行全面而深入的分析,深刻揭示JVM的工作原理。以實(shí)踐為導(dǎo)向,通過大量與實(shí)際生產(chǎn)環(huán)境相結(jié)合的案例展示了解...
閱讀 687·2021-11-15 11:39
閱讀 2919·2021-10-08 10:04
閱讀 3285·2019-08-30 10:57
閱讀 3040·2019-08-26 13:25
閱讀 1930·2019-08-26 12:14
閱讀 2656·2019-08-23 15:27
閱讀 3014·2019-08-23 15:18
閱讀 1796·2019-08-23 14:26