日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
為什么Java程序會(huì)執(zhí)行一段時(shí)間后跑的更快?

對(duì)于Java 應(yīng)用,程序員之間一個(gè)認(rèn)識(shí)口口相傳:

創(chuàng)新互聯(lián)建站專業(yè)為企業(yè)提供沁陽網(wǎng)站建設(shè)、沁陽做網(wǎng)站、沁陽網(wǎng)站設(shè)計(jì)、沁陽網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、沁陽企業(yè)網(wǎng)站模板建站服務(wù),十年沁陽做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

要看一個(gè)Java程序跑的快不快,需要多跑幾次;另外,Java程序跑一段時(shí)間之后會(huì)快起來。速度甚至能趕上 C/C++程序的速度。

如果你問為什么跑一段時(shí)間就快了呢?

一般都能聽到 「因?yàn)镴VM會(huì)把調(diào)用次數(shù)多的熱方法編譯再執(zhí)行」的答案。

更通俗的話來講, JVM 會(huì)把熱方法編譯成機(jī)器碼,執(zhí)行效率會(huì)更高。就像公司或工廠里,對(duì)于一項(xiàng)任務(wù),一般老手都比新人更快,因?yàn)槔鲜指煜ぢ?。所以招聘要求里你很少?huì)見到指明要新人的,大部分都是要有工作經(jīng)驗(yàn)的。

而JVM 將熱方法編譯生成的機(jī)器碼,由于是針對(duì)當(dāng)前平臺(tái),當(dāng)前硬件生成的,對(duì)應(yīng)用具體執(zhí)行情況分析之后進(jìn)行編譯而成,所以就像老手一樣,能更了解情況,效率當(dāng)然更高。

默默在背后做編譯工作的人就是 JIT (Just-In-Time) 編譯器,一般也叫即時(shí)編譯器。

今天我們一起來看看,這越跑越快的背后,JIT 具體是怎樣工作的。

我們都知道,Java 原生就是解釋型語言,也是解釋執(zhí)行的,怎么又有了編譯執(zhí)行了?

執(zhí)行 java -version 的時(shí)候,我們一般能看到當(dāng)前 Java 版本號(hào)之后,會(huì)有一個(gè) mixed mode,說明當(dāng)前JVM 運(yùn)行在混合模式之下,即同時(shí)包含解釋執(zhí)行和編譯執(zhí)行。我們也可以通過參數(shù)強(qiáng)制執(zhí)行只按一種模式執(zhí)行。各種環(huán)境根據(jù)自己的需要選擇執(zhí)行的方式。

相比編譯執(zhí)行,解釋執(zhí)行要慢很多,但仍然廣泛在被運(yùn)用在各種虛擬機(jī)中,比如它內(nèi)存占用少,應(yīng)用啟動(dòng)時(shí)間更短。更關(guān)鍵的優(yōu)勢在于它簡單。一種新語言或者一個(gè)語言的新特性出現(xiàn)時(shí),在解釋器中能比編譯器實(shí)現(xiàn)要快很多。另外,開發(fā)者會(huì)考慮到性價(jià)比,一些語言特性很難,同時(shí)也不值得在實(shí)現(xiàn)在編譯器就只使用解釋器。

開發(fā)實(shí)現(xiàn)語言時(shí),使用解釋器只有兩個(gè)要求:

  1. 熟悉VM實(shí)現(xiàn)語言
  2. 理解新語言特性、語法和語義

而像在JIT編譯器實(shí)現(xiàn)新語言特性,對(duì)開發(fā)者有更多的要求:

  • 熟悉目標(biāo)機(jī)器的應(yīng)用程序二進(jìn)制接口規(guī)范
  • 把新語言特性映射到這個(gè)目標(biāo)機(jī)器的接口運(yùn)行時(shí)
  • 掌握開發(fā)編譯器生成目標(biāo)機(jī)器碼的能力

而為了應(yīng)用程序的執(zhí)行效率、運(yùn)行速度, Java 又特別需要JIT,在運(yùn)行的適當(dāng)時(shí)候,可以把一些高頻率代碼編譯,換取更好的效率。

JIT就是通過將熱方法、代碼段編譯生成機(jī)器碼的形式,在下次調(diào)用到該方法時(shí),會(huì)直接通過vtable中鏈接的機(jī)器碼直接執(zhí)行,所以效率是杠杠的。

那么問題來了,什么樣的方法才算熱方法,怎樣來判斷熱方法?

對(duì)于熱方法的計(jì)算,一般虛擬機(jī)內(nèi)有以下幾種實(shí)現(xiàn)方式:

  • 基于方法的JIT,JVM內(nèi)常用
  • 基于蹤跡的JIT, Dalvik和 TraceMonkey在使用
  • 基于區(qū)域的JIT,HHVM 使用這種形式

基于方法的JIT中,一般探測熱點(diǎn)方法有基于采樣的熱點(diǎn)探測,即周期性的去檢查線程的調(diào)用棧頂,如果方法經(jīng)常出現(xiàn)在棧頂,那它就是熱點(diǎn)方法。另一種是基于計(jì)數(shù)器的熱點(diǎn)探測,這種會(huì)給每個(gè)方法建立計(jì)數(shù)器,用來統(tǒng)計(jì)方法的執(zhí)行次數(shù)。超過閾值的就認(rèn)為是熱點(diǎn)方法。

當(dāng)然需要注意的是,這里統(tǒng)計(jì)的次數(shù),不是絕對(duì)的次數(shù),和我們進(jìn)行限流和降級(jí)時(shí)說的類似,都是一個(gè)時(shí)間周期內(nèi)的相對(duì)頻率,如果在此期間沒有超過,就不算,原來的次數(shù)會(huì)減少。

JIT 編譯的代碼,存儲(chǔ)在 Code Cache 的內(nèi)存區(qū)間??臻g是有限的在JVM 啟動(dòng)的時(shí)候,設(shè)置了一個(gè)固定的最大值,實(shí)現(xiàn)形式也是個(gè)堆,在分配滿時(shí)會(huì)停止編譯,類卸載、替換成新版本等也會(huì)從 Code Cache中刪除。

另外,在JVM JIT編譯器中包含C1、C2 兩種編譯器,在具體的編譯過程中,一般是采用分層編譯,再具體使用不同的編譯器,相比C1,C2編譯需要更多的時(shí)間,做更多的優(yōu)化等等,像內(nèi)聯(lián)、循環(huán)展開、逃逸分析、鎖消除與合并、棧上替換……

前面我們大概了解了JIT的原理,也了解到 JIT 編譯后,機(jī)器碼執(zhí)行效率更高,那有什么辦法能了解到我們自己的應(yīng)用里,JIT有沒有執(zhí)行,用的是C1還是C2,對(duì)哪些代碼做過編譯和優(yōu)化呢?

我們有沒有辦法,能知道都有哪些方法被JIT編譯了,哪些方法本來我們想要效率高一些,期待被編譯卻沒被考慮的,能更直觀的知道呢?

一個(gè)辦法是應(yīng)用啟動(dòng)時(shí),增加 JVM 參數(shù):

  • -XX:+UnlockDiagnosticVMOptions
  • -XX:+PrintCompilation
  • -XX:+PrintInlining
  • -XX:+PrintCodeCache
  • -XX:+PrintCodeCacheOnCompilation
  • -XX:+TraceClassLoading
  • -XX:+LogCompilation
  • -XX:LogFile=~/a.log

然后根據(jù)這些輸出內(nèi)容,以及日志文件里的內(nèi)容,去分析。

當(dāng)然,如果真的是肉眼閱讀那可太累了。好在有一個(gè)優(yōu)秀的開源工具用于解析日志文件。

鐺鐺鐺,來了。

就是它, JITWatch。

https://github.com/AdoptOpenJDK/jitwatch

使用 JavaFX 開發(fā)而成,功能很強(qiáng)大。

你可以 通過 Open Log 直接解析上面輸出的日志文件。 例如一個(gè)簡單的應(yīng)用,打開日志之后,會(huì)看到不同包下的內(nèi)容,這里example111 是示例。

 
 
 
 
  1. public void jitTest() { 
  2.         long x = calc(); 
  3.         System.out.println(x); 
  4.     } 
  5.  
  6.     public long calc() { 
  7.         long sum = 0; 
  8.         for (long i=0; i< 1000000; i++) { 
  9.             sum = plus(sum, i); 
  10.         } 
  11.         return sum; 
  12.     } 
  13.  
  14.     public long  plus(long a, long b) { 
  15.         return a + b; 
  16.     } 

在點(diǎn)擊右側(cè)某個(gè)JIT編譯過的具體方法后,點(diǎn)擊TriView,會(huì)看到生成的節(jié)字碼,以及相應(yīng)的源碼是如何對(duì)應(yīng)到字節(jié)碼和匯編代碼的。

點(diǎn)擊Chain,會(huì)看到編譯鏈路

Inline-info 會(huì)顯示哪些方法進(jìn)行了內(nèi)聯(lián)優(yōu)化。

這里看到的OSR,就是常聽到的棧上替換(On-stack replacement),用于優(yōu)化在解釋器中執(zhí)行時(shí),向后跳轉(zhuǎn)的循環(huán)分支達(dá)到某個(gè)閾值時(shí)就會(huì)被編譯。

JITWatch 還有一個(gè)沙箱的環(huán)境,可以用來實(shí)驗(yàn)觀察 JIT的行為,觀察 JVM 里JIT的決策過程。

有了工具的幫助,我們能更好的理解JIT 對(duì)應(yīng)用優(yōu)化的決策,從而讓應(yīng)用性能更佳。


文章標(biāo)題:為什么Java程序會(huì)執(zhí)行一段時(shí)間后跑的更快?
文章分享:http://www.5511xx.com/article/djespdc.html