編譯器優化機制詳解

編譯器優化機制詳解

1 字節碼是如何執行的?

主要包含解釋執行(由解釋器一行一行翻譯執行)和編譯執行(將字節碼編譯成機器碼,直接執行機器碼)。

  • 解釋執行:優勢在於沒有編譯的等待時間,性能相對編譯執行差。
  • 編譯執行:運行效率高,比解釋執行快一個數量級;會帶來額外的開銷(CPU,內存)

查看和切換運行模式

>java -version
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode) // 混合模式

C:\Users\lizho>java -Xint -version
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, interpreted mode)

-Xint // 解釋執行
-Xcomp // 編譯模式,不能編譯的解釋執行
-Xmixed // 混合模式

通常一開始使用解釋器解釋執行。當虛擬機發現某個方法或者代碼塊執行頻繁時,便判定這些代碼爲熱點代碼。爲了提高這部分代碼的執行效率,會採用即時編譯器JIT,將熱點代碼編譯成與本地平臺相關的機器碼,並進行分層優化

2 Hotspot即時編譯

C1/C2編譯器

C1編譯器,是客戶端編譯器,簡單快速,主要關注局部的優化。適用於執行時間較短或對啓動性能有要求的程序。例如,GUI應用對界面啓動速度就有一定要求。

C2編譯器,是服務端編譯器,主要爲長期運行的服務器端應用程序做性能調優,適用於執行時間較長或對峯值性能有要求的程序。

分層編譯

Hotspot默認開啓分層編譯,分層編譯分爲5層。

  1. 解釋執行
  2. 簡單C1編譯:會用C1編譯器進行一些簡單的優化,不開啓 Profiling(JVM監控)。
  3. 受限的C1編譯:僅執行帶方法調用次數以及循環回邊執行次數Profiling的C1編譯
  4. 完全C1編譯:會執行帶有所有 Profiling的C1代碼
  5. C2編譯∶使用C2編譯器進行優化,該級別會啓用一些編譯耗時較長的優化,一些情況下會根據性能監控信息進行一些非常激進的性能優化

級別越高,應用啓動越慢,優化的開銷越高,峯值性能也越高。

# 只想開啓C2層,只能做到禁用中間編譯層(123層)
-XX:-TieredCompilation
# 只想開啓C1層,生效0和1層
-XX:-TieredCompilation -XX:TieredStopAtLevel=1

3 JVM如何找到熱點代碼?

基於採樣的熱點探測。通過採樣,不斷探測棧頂,發現哪個方法執行次數多;

基於計數器的熱點探測。統計方法的執行次數,由此判斷熱點方法。Hotspot使用計數器方法。

Hotspot內置兩類計數器

方法調用計數器( Invocation Counter)

用於統計方法被調用的次數,在不開啓分層編譯的情況下,在C1編譯器下的默認閾值是1500次,在C2模式下是10000次。也可用-XX: CompileThreshold=X指定閾值。

方法調用計數器默認統計的是一個相對的執行頻率,即一段時間之內方法被調用的次數。如果超過時間限度,仍然不滿足編譯閾值,則計數器減少一半,這個過程稱爲計數器熱度衰減,這段時間稱爲半衰週期。

-XX:-UseCounterDecay 關閉熱度衰減,使計數器統計方法調用的絕對次數。只要時間夠長,大多數方法都會編譯成本地代碼。
-XX:CounterHalfLifeTime 設置半衰週期s。

image

【注意】JVM按照兩個計數器之和判斷是否需要編譯。

回邊計數器( Back Edge Counter)

用於統計—個方法中循環體代碼執行的次數,在字節碼中遇到控制流向後跳轉的指令稱爲“回邊”( Back Edge)。在不開啓分層編譯的情況下,C1編譯器下的默認閾值13995,C2默認爲10700,可使用-XX:OnStackReplacePercentage=X指定閾值

建立回邊計數器的主要目的是爲了觸發OSR(OnStackReplacement棧上替換)編譯(介紹略)。回邊計數器的流程圖跟上圖類似,不同的是向編譯器發起OSR請求。

當開啓了分層編譯,JVM會根據當前帶編譯的方法數以及編譯線程數動態調整閾值。上面的兩個參數失效。

JVM參數小結

image

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