怎么使用javaHotspot虛擬機(jī)內(nèi)的即時(shí)編譯器

這篇文章主要介紹“怎么使用java Hotspot虛擬機(jī)內(nèi)的即時(shí)編譯器”,在日常操作中,相信很多人在怎么使用java Hotspot虛擬機(jī)內(nèi)的即時(shí)編譯器問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么使用java Hotspot虛擬機(jī)內(nèi)的即時(shí)編譯器”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

建安ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)建站的ssl證書銷售渠道,可以享受市場價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!

在部分商用虛擬機(jī)(SunHotspot、IBMJ9)中,Java程序最初是通過解釋器解釋執(zhí)行的,當(dāng)虛擬機(jī)發(fā)現(xiàn)有個(gè)方法或代碼塊運(yùn)行特別頻繁時(shí),就會(huì)把這些代碼認(rèn)定為“熱點(diǎn)代碼”。為了提高熱點(diǎn)代碼的執(zhí)行效率,虛擬機(jī)會(huì)把這些代碼編譯成與本地平臺相關(guān)的機(jī)器碼,并進(jìn)行各種層次的優(yōu)化,完成這個(gè)任務(wù)的編譯器被稱為即時(shí)編譯器(JustInTimeCompiler,簡稱JIT編譯器)。即時(shí)編譯器并不是虛擬機(jī)必須的部分,但是即時(shí)編譯器編譯性能的好壞、代碼優(yōu)化程度的高低卻是衡量一款商用虛擬機(jī)好壞與否最關(guān)鍵的指標(biāo)之一,是虛擬機(jī)中最核心且最能體現(xiàn)虛擬機(jī)技術(shù)水平的部分。

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

重點(diǎn)我們需要關(guān)注解決以下幾個(gè)問題:

為何Hotspot虛擬機(jī)要使用解釋器和編譯器并存的架構(gòu)?
為何Hotspot虛擬機(jī)要實(shí)現(xiàn)兩個(gè)不同的即時(shí)編譯器?
程序何時(shí)使用解釋器執(zhí)行?何時(shí)使用編譯器執(zhí)行?
哪些程序代碼會(huì)被編譯為本地代碼?如何編譯為本地代碼?
如何從外部觀察即時(shí)編譯器的編譯過程和編譯結(jié)果?

解釋器與編譯器

盡管不是所有的Java虛擬機(jī)都采樣解釋器與編譯器并存的架構(gòu),但是許多主流的虛擬機(jī),比如SunHotspot、IBMJ9,都同時(shí)包含解釋器與編譯器。解釋器與編譯器有各自的優(yōu)勢:當(dāng)程序需要快速啟動(dòng)時(shí),解釋器可以發(fā)揮作用,省去編譯時(shí)間立即執(zhí)行。在程序運(yùn)行后,隨著時(shí)間的推移,編譯器逐漸發(fā)揮作用,把越來越多的代碼編譯成本地代碼后,可以獲取更高的執(zhí)行效率。
當(dāng)程序運(yùn)行環(huán)境的內(nèi)存資源限制較大時(shí),使用解釋器執(zhí)行節(jié)省內(nèi)存,反之可以使用編譯執(zhí)行提升效率。同時(shí),解釋器還可以作為編譯器激進(jìn)優(yōu)化時(shí)的一個(gè)“逃生門”,讓編譯器根據(jù)概率選擇一個(gè)大多數(shù)時(shí)候都能提升運(yùn)行速度的優(yōu)化手段,當(dāng)激進(jìn)優(yōu)化的假設(shè)不成立時(shí),比如加載了新類后類型繼承結(jié)構(gòu)出現(xiàn)變化,出現(xiàn)“罕見陷阱”時(shí)可以通過逆優(yōu)化退回到解釋狀態(tài)繼續(xù)執(zhí)行。因此,在虛擬機(jī)中解釋器和編譯器經(jīng)常配合工作,如下圖所示:

                                    怎么使用java Hotspot虛擬機(jī)內(nèi)的即時(shí)編譯器

                                                         圖-解釋器與編譯器的交互

HotSpot虛擬機(jī)內(nèi)置了兩個(gè)即時(shí)編譯器:ClientCompiler和ServerCompiler,簡稱C1編譯器和C2編譯器。默認(rèn)采用解釋器和其中一個(gè)編譯器直接配合的方式工作,具體使用哪個(gè)編譯器,取決于虛擬機(jī)工作的模式,用戶可以使用-client參數(shù)或-server參數(shù)指定虛擬機(jī)的工作模式,還可以使用-Xint強(qiáng)制虛擬機(jī)運(yùn)行于“解釋模式”。
由于即時(shí)編譯器編譯本地代碼需要占用程序運(yùn)行時(shí)間,要編譯出優(yōu)化程度更高的代碼,所需時(shí)間會(huì)更長。同時(shí),解釋器還要替編譯器收集性能監(jiān)控信息,這對解釋執(zhí)行速度也有影響。為了在程序啟動(dòng)響應(yīng)速度與運(yùn)行效率之間達(dá)到最佳平衡,HotSpot虛擬機(jī)又引入了分層編譯的策略。分層編譯根據(jù)編譯器編譯、優(yōu)化的規(guī)模與耗時(shí),劃分為不同的編譯層次,包括:
第0層,程序解釋執(zhí)行,不開啟性能監(jiān)控功能,可觸發(fā)第1層編譯。
第1層,稱為C1編譯,將字節(jié)碼編譯為本地代碼,并進(jìn)行簡單可靠的優(yōu)化,如有必要將加入性能監(jiān)控邏輯。
第2層,稱為C2編譯,也是將字節(jié)碼編譯為本地代碼,但是會(huì)進(jìn)行耗時(shí)較長的優(yōu)化,甚至?xí)鶕?jù)性能監(jiān)控信息進(jìn)行一些不完全可靠的激進(jìn)優(yōu)化。
實(shí)施分層編譯后,ClientCompiler和ServerCompiler會(huì)同時(shí)工作,許多代碼可能會(huì)被編譯多次,用ClientCompiler獲得更快的編譯速度,用ServerCompiler獲取更好的編譯質(zhì)量,在解釋執(zhí)行的時(shí)候也無需再承擔(dān)收集性能監(jiān)控信息的任務(wù)。

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

在運(yùn)行過程中,會(huì)被即時(shí)編譯器編譯的熱點(diǎn)代碼有兩類:
被多次調(diào)用的方法。
被多次執(zhí)行的循環(huán)體。
這兩種情況,編譯器都會(huì)編譯整個(gè)方法。因?yàn)榫幾g發(fā)生在方法執(zhí)行過程中,因此形象地稱之為棧上替換(OnStackReplacement,簡稱OSR,即方法棧幀還在棧上,方法就被替換了)。
判斷一段代碼是不是熱點(diǎn)代碼,是否需要觸發(fā)即時(shí)編譯,這樣的行為稱為熱點(diǎn)探測(HotSpotDetection),熱點(diǎn)探測方式主要有兩種:
基于采樣的熱點(diǎn)探測:采用這種方法的虛擬機(jī)會(huì)周期性地檢查各個(gè)線程的棧頂,如果某個(gè)方法經(jīng)常出現(xiàn)在棧頂,那它就是熱點(diǎn)方法。其優(yōu)點(diǎn)是簡單、高效,還可以獲取方法調(diào)用關(guān)系;缺點(diǎn)是不夠精確,容易受到線程阻塞或其他外接因素的影響。
基于計(jì)數(shù)的熱點(diǎn)探測:采用這種方法的虛擬機(jī)會(huì)為每個(gè)方法(甚至是代碼塊)建立計(jì)數(shù)器,統(tǒng)計(jì)方法執(zhí)行次數(shù),次數(shù)超過一定閾值就認(rèn)為是熱點(diǎn)方法。這種方法實(shí)現(xiàn)起來麻煩,但是其統(tǒng)計(jì)結(jié)果相對來說更加精確和嚴(yán)謹(jǐn)。
在HotSpot虛擬機(jī)里使用的是第二種方法,因此它為每個(gè)方法準(zhǔn)備了兩類計(jì)數(shù)器:方法調(diào)用計(jì)數(shù)器(InvocationCounter)回邊計(jì)數(shù)器(BackedgeCounter)。在確定虛擬機(jī)運(yùn)行參數(shù)的情況下,這兩個(gè)計(jì)數(shù)器都有一定的閾值,超過閾值就會(huì)觸發(fā)JIT編譯。

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

Java虛擬機(jī)設(shè)計(jì)團(tuán)隊(duì)幾乎對代碼的所有優(yōu)化措施都集中在了即時(shí)編譯器中,因此一般來說,即時(shí)編譯器產(chǎn)生的本地代碼會(huì)比javac產(chǎn)生的字節(jié)碼更加優(yōu)秀。下面,我們介紹一些HotSpot虛擬機(jī)即時(shí)編譯器生成代碼時(shí)采用的代碼優(yōu)化技術(shù)。

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

公共子表達(dá)式消除是一個(gè)普遍應(yīng)用于各種編譯器的經(jīng)典優(yōu)化技術(shù),它的原理是:如果一個(gè)表達(dá)式E已經(jīng)計(jì)算過了,并且從先前計(jì)算到現(xiàn)在E中所有變量的值都沒有發(fā)生變化,那么E的這次計(jì)算就稱為公共子表達(dá)。對于這種表達(dá)式,就沒有必要再對其進(jìn)行計(jì)算了,使用之前計(jì)算過的值即可。

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

數(shù)組邊界檢查消除是即時(shí)編譯器中語言相關(guān)的經(jīng)典優(yōu)化技術(shù)。如果有一個(gè)數(shù)組foo[],Java語言在訪問數(shù)組元素foo[i]時(shí),系統(tǒng)會(huì)自動(dòng)進(jìn)行上下界的范圍檢查,即i的取值范圍是0~foo.length-1,否則將拋出運(yùn)行時(shí)異常java.lang.ArrayIndexOutOfBoundsException。這對開發(fā)者來說是好事情,即時(shí)程序員沒有專門編寫防御代碼,也可以避免大部分的溢出攻擊。但是,對于虛擬機(jī)的執(zhí)行子系統(tǒng)來說,每次數(shù)組元素的讀寫操作都帶有一次隱含的條件判定操作,對于擁有大量數(shù)組訪問的系統(tǒng),無疑是一種性能上的負(fù)擔(dān)。
編譯器會(huì)對代碼進(jìn)行分析,如果確定某次數(shù)組訪問一定不會(huì)越界,就可以去掉數(shù)組的上下界檢查。比如在循環(huán)訪問數(shù)組時(shí),編譯器只要通過數(shù)據(jù)流分析確定循環(huán)變量的取值范圍一定在[0,foo.length)之間,就可以在整個(gè)循環(huán)中把數(shù)組上下界檢查消除。
與數(shù)組邊界檢查消除類似的優(yōu)化,還有隱式異常處理,Java中空指針檢查和除數(shù)為零檢查都采用了這種思路。

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

方法內(nèi)聯(lián)看起來簡單,但實(shí)際中很多方法都無法直接進(jìn)行內(nèi)聯(lián)。原因是除了使用invokespecial指令調(diào)用的私有方法、實(shí)例構(gòu)造器、父類方法以及使用invokestatic指令調(diào)用的靜態(tài)方法,還有部分final方法能夠在編譯時(shí)唯一確定執(zhí)行的方法版本,其他都可能存在多于一個(gè)版本的方法接收者,需要在運(yùn)行時(shí)才能確定,這一類方法稱為虛方法,由于Java語言提倡使用面向?qū)ο蟮木幊谭绞竭M(jìn)行編程,而Java語言默認(rèn)的實(shí)例方法就是虛方法,因此內(nèi)聯(lián)與虛方法之間產(chǎn)生矛盾。
對于一個(gè)虛方法,編譯期做內(nèi)聯(lián)的時(shí)候根本無法確定應(yīng)該使用哪個(gè)方法的版本,為了解決虛方法的內(nèi)聯(lián)問題,Java虛擬機(jī)引入了一種稱為“類型繼承關(guān)系分析”(ClassHierarchyAnalysis,CHA)的技術(shù),這是一種基于整個(gè)應(yīng)用程序的類型分析技術(shù),它用于確定在目前已加載的類中,某個(gè)接口是否有多于一種實(shí)現(xiàn),某個(gè)類是否存在子類、子類是否為抽象類等信息。
非虛方法可以直接內(nèi)聯(lián),如果是虛方法且通過CHA分析得知某個(gè)方法只有一個(gè)版本那也可以進(jìn)行內(nèi)聯(lián),不過這種內(nèi)聯(lián)屬于“激進(jìn)優(yōu)化”,需要預(yù)留一個(gè)“逃生門”,稱為守護(hù)內(nèi)聯(lián)。如果程序在執(zhí)行過程中,虛擬機(jī)一直沒有加載到令這個(gè)類繼承關(guān)系發(fā)生變化的類,那這個(gè)內(nèi)聯(lián)優(yōu)化的代碼就可以一直使用下去。但如果加載了導(dǎo)致繼承關(guān)系發(fā)生變化的新類,那就需要拋棄已經(jīng)編譯的代碼,返回到解釋狀態(tài)執(zhí)行,或者重新進(jìn)行編譯。
如果CHA查出來某方法有多個(gè)版本,則編譯器還會(huì)進(jìn)行最后一次努力,使用內(nèi)聯(lián)緩存InlineCache來完成方法內(nèi)聯(lián),這是一個(gè)建立在目標(biāo)方法正常入口之前的緩存,其工作原理是:在未發(fā)生方法調(diào)用之前,內(nèi)聯(lián)緩存為空,當(dāng)?shù)谝淮握{(diào)用發(fā)生后,緩存記錄下方法接收者的版本信息。后續(xù)每次執(zhí)行都檢查版本,如果以后進(jìn)來的每次調(diào)用的方法接受者版本都是一樣的,那么這個(gè)內(nèi)聯(lián)還可以一直使用下去,否則查找虛方法表進(jìn)行方法分派。

逃逸分析

逃逸分析是目前Java虛擬機(jī)中比較前沿的優(yōu)化技術(shù),它與類型繼承關(guān)系分析一樣,并不是直接優(yōu)化代碼的技術(shù),而是為其他優(yōu)化手段提供依據(jù)的分析技術(shù)。逃逸分析的基本行為是分析對象動(dòng)態(tài)作用域:當(dāng)一個(gè)對象在方法里定義后,它可能被外部方法所引用,例如作為調(diào)用參數(shù)傳遞到其他方法中,稱為方法逃逸。甚至還有可能被外部線程訪問到,譬如賦值給類變量或其他線程中訪問的實(shí)例變量,稱為線程逃逸
如果能證明一個(gè)對象不會(huì)逃逸到方法或線程之外,就可以為這個(gè)變量進(jìn)行一些高效優(yōu)化:
棧上分配:Java一般是在堆上分配對象的,對象的回收依賴虛擬機(jī)的垃圾收集系統(tǒng),垃圾收集系統(tǒng)回收和整理內(nèi)存都需要耗費(fèi)時(shí)間。如果一個(gè)對象不會(huì)逃逸出方法之外,那讓這個(gè)對象在棧上分配會(huì)是一個(gè)不錯(cuò)的主意,對象所占用的內(nèi)存空間可以隨著棧幀出棧而銷毀,減輕了垃圾收集系統(tǒng)的壓力。
同步消除:線程同步本身是一個(gè)相對耗時(shí)的過程,如果逃逸線程分析確定一個(gè)對象不會(huì)逃逸出線程,不會(huì)被其他線程訪問,那這個(gè)變量的讀寫肯定不會(huì)有競爭,對這個(gè)變量實(shí)施的同步措施也就可以消除掉。
標(biāo)量替換:標(biāo)量是指一個(gè)數(shù)據(jù)已經(jīng)無法再分解成更小的數(shù)據(jù)了,Java中的原始數(shù)據(jù)類型都不能再進(jìn)一步分解,就可以稱為標(biāo)量。相對的,如果一個(gè)數(shù)據(jù)可以繼續(xù)分解,就可以稱作聚合量,Java中的對象就是典型的聚合量。如果把一個(gè)Java對象拆散,根據(jù)程序訪問情況,將其使用到的成員變量恢復(fù)原始類型來訪問就叫做標(biāo)量替換。如果逃逸分析證明一個(gè)對象不會(huì)被外部訪問,并且這個(gè)對象可以被拆散的話,那程序真正執(zhí)行的時(shí)候就可能不創(chuàng)建這個(gè)對象,改為直接創(chuàng)建它的若干個(gè)成員變量來代替。將對象拆分后,除了可以讓成員變量在棧上分配和讀寫外,還可以為后續(xù)進(jìn)一步優(yōu)化創(chuàng)建條件。

需要注意逃逸分析的性能收益是否低于它的消耗。如果要完全準(zhǔn)確地判斷一個(gè)對象是否會(huì)逃逸,需要進(jìn)行數(shù)據(jù)流敏感的一系列復(fù)雜分析,從而確定程序各個(gè)分支執(zhí)行時(shí)對此對象的影響,這是一個(gè)相對耗時(shí)的過程,如果分析發(fā)現(xiàn)沒有幾個(gè)不逃逸的對象,那這些運(yùn)行期耗用的時(shí)間就白白浪費(fèi)了,所以目前虛擬機(jī)只能采用不那么準(zhǔn)確,但時(shí)間壓力相對較小的算法來完成逃逸分析。

到此,關(guān)于“怎么使用java Hotspot虛擬機(jī)內(nèi)的即時(shí)編譯器”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

網(wǎng)站欄目:怎么使用javaHotspot虛擬機(jī)內(nèi)的即時(shí)編譯器
網(wǎng)頁地址:http://bm7419.com/article20/gijcco.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、App設(shè)計(jì)、微信公眾號、手機(jī)網(wǎng)站建設(shè)網(wǎng)站收錄、網(wǎng)站改版

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站制作