JIT 編譯器如何最佳化程式碼

當選擇方法進行編譯時, JVM 會將其位元組碼提供給 Just-In-Time 編譯器 (JIT)。 JIT 需要先瞭解位元組碼的語意和語法,才能正確編譯方法。

為了協助 JIT 編譯器分析方法,它的位元組碼首先在稱為 樹狀結構的內部表示法中重新表述,它與機器碼的相似程度比位元組碼更接近。 然後會對方法的樹狀結構執行分析及最佳化。 最後,樹狀結構會轉換成原生程式碼。 本節的其餘部分提供 JIT 編譯階段的簡要概觀。 如需相關資訊,請參閱 診斷 JIT 或 AOT 問題

JIT 編譯器可以使用多個編譯執行緒來執行 JIT 編譯作業。 使用多個執行緒可能有助於 Java 應用程式更快啟動。 實際上,只有在系統中有未用的處理核心時,多個 JIT 編譯執行緒才會顯示效能改進。

預設編譯執行緒數目由 JVM 識別,且取決於系統配置。 如果產生的執行緒數目不是最佳的數目,您可以使用 -XcompilationThreads 選項來置換 JVM 決策。 如需使用此選項的相關資訊,請參閱 -X 選項
附註: 如果您的系統沒有未用的處理核心,增加編譯執行緒數目不太可能提高效能。

編譯包含下列階段。 除了原生程式碼產生以外的所有階段都是跨平台程式碼。

第 1 階段-列入

列入是指將較小方法的樹狀結構 (或「列入」) 合併至其呼叫端的樹狀結構的程序。 這會加速經常執行的方法呼叫。 視現行最佳化層次而定,會使用兩種具有不同等級的列入演算法。 在此階段執行的最佳化包括:
  • 瑣碎列入
  • 呼叫曲線列入
  • 尾遞迴排除
  • 虛擬呼叫保護最佳化

階段 2-本端最佳化

本端最佳化會一次分析並改善程式碼的一小部分。 許多本端最佳化實作在標準靜態編譯器中使用的已嘗試及已測試技術。 最佳化包括:
  • 本端資料流程分析及最佳化
  • 登錄使用情形最佳化
  • 簡化 Java 慣用句
這些技術反覆應用,特別是在全球優化之後,可能指出更多的改進機會。

階段 3-控制流程最佳化

控制流程最佳化會分析方法 (或其特定區段) 內的控制流程,並重新排列程式碼路徑以提高其效率。 最佳化為:
  • 重新排序、分割及移除程式碼
  • 迴路縮減與反轉
  • 迴圈跨及迴圈不變碼運動
  • 開卷剝離環
  • 迴圈版本化和特殊化
  • 異常狀況導向最佳化
  • 交換器分析

階段 4-廣域最佳化

廣域最佳化一次在整個方法上運作。 它們更「昂貴」,需要大量的編譯時間,但可以大幅增加效能。 最佳化為:
  • 廣域資料流程分析及最佳化
  • 局部冗餘排除
  • 跳出分析
  • GC 及記憶體配置最佳化
  • 同步化最佳化

階段 5-原生程式碼產生

原生程式碼產生程序會因平台架構而異。 一般而言,在編譯的這個階段,方法的樹狀結構會轉換成機器碼指令; 一些小型最佳化會根據架構性質來執行。 編譯後的程式碼會放入 JVM 程序空間的一部分 (稱為 程式碼快取); 會記錄方法在程式碼快取中的位置,以便未來對它的呼叫會呼叫編譯後的程式碼。 在任何給定時間, JVM 程序都由 JVM 執行檔及一組 JIT 編譯程式碼組成,這些程式碼會動態鏈結至 JVM 中的位元組碼直譯器。