jvm 解釋器和編譯器 原

在商用虛擬機中,Java程序最初是通過解釋器(Interpreter)進行解釋執行的,當虛擬機發現某個方法或者代碼塊運行特別頻繁時 就會把這些代碼認定爲“熱點代碼”,爲了提高熱點代碼的執行效率,在運行時,虛擬機將會把這些代碼編譯成與本地平臺相關的機器碼 ,完成這個任務的編譯器成爲即時編譯器(JIT Just In Time Compiler)

解釋器

當程序需要迅速啓動和執行的時候,解釋器可以首先發揮作用,省去編譯的時間,立即執行。

編譯器

程序運行後隨着時間的推移,編譯器逐步發揮作用,把越來越多的代碼編譯成本地代碼之後,可以獲得更高的執行效率。

編輯的“熱點代碼” 有以下兩類:

  • 被多次調用的方法
  • 被多次執行的循環體

第一種是由於方法被調用觸發的編譯,編譯器理所當然以整個方法作爲編譯對象,這種編譯也是虛擬機中標準的JIT編譯方式。對於後一種情況 ,儘管是循環體,但是編譯器依然會以整個方法作爲編譯對象,而不是單獨的循環體。這種逼啊安逸方式因爲編譯放生在方法執行過程之中,因 此被形象的成爲"棧上替換"(On Stack Replacement ,簡稱OSR編譯,即方法棧幀還在棧上,方法就被替換了)

還有一個問題是什麼叫做多次,多次是指多少次?還有一個問題就是虛擬機如何統計一個方法執行的次數?解決了這個問題也就回答了即時編譯 觸發的條件。
判斷一段代碼是不是熱點代碼,是不是需要觸發即時編譯,這樣的行爲成爲熱點探測 ,其實熱點探測並不需要一定要知道方法具體被調用 了多少次,目前主要的熱點探測的方式有如下兩種:

  • 基於採樣的熱點探測:這種方式虛擬機會週期性的檢查各個線程的棧頂,如果發現某個方法經常出現在棧頂,這個方法就是“熱點方法”。採 樣的方法簡單,高效,並且還能比較容易的獲取調用鏈,缺點是很難比較有精度的確認一個方法的精度,容易受到線程阻塞或者別的外界因素影 響。
  • 基於計數的熱點探測:這種方法虛擬機會爲每個方法(甚至是代碼塊)建立計數器,統計方法的執行次數,如果執行次數超過一定的閾值就會 被認定爲“熱點方法”。這種統計方式比較麻煩,需要爲每個方法維護一個計數器,但是比較精準。
    HotSpot虛擬機採用的是第二種,基於計數器熱點探測方式。因此它爲每個方法準備了兩類計數器,方法調用計數器和回邊計數器。

方法調用計數器,顧名思義,就是統計方法調用的次數,在client模式下,是1500次,在server模式下是10000次。這個閾值可以通過虛擬 機參數-XX::CompileThreadhold來人爲設定。方法調用時,先檢查是否存在被JIT編譯後的版本,存在的話則優先使用編譯後的本地代碼, 不存在則將此方法計數器+1,然後判斷方法調用計數器和回邊計數器紙盒是否超過方法調用計數器的閾值。超過的話就發送及時編譯請求。

這個次數不是絕對的次數,而是一個相對的執行頻率,即一段時間之內方法被調用的次數,當超過一定的時間限度,如果方法的調用次數仍然不足 以讓他提交給即時編譯器編譯,那這個方法的調用計數器會被減少一半,這個過程被成爲方法調用計數器熱度衰減,而這段週期就稱爲半衰週期。 進行熱度衰減的動作是在垃圾回收時順便進行的,可以使用虛擬機參數 -XX:-UseCounterDecay來關閉熱度衰減,可以使用 -XX:CounterHalfLifeTime 參數設置半衰週期的時間,單位是秒。 另外一種計數器——“回邊計數器”,它的作用是統計方法中循環體代碼的執行次數,在字節碼中遇到控制流向後跳轉的指令成爲“回邊”。目的 也是爲了觸發OSR編譯。與方法計數器不同,回邊計數器沒有計算熱度衰減的過程,因此這個計數器就是該方法循環的絕對次數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章