提前加載和連結課程
1. 引言
JDK 24 透過JEP 483引入了 AOT 快取。此快取允許應用程式透過預先載入和預連結類別來加快啟動速度。然而,創建快取的工作流程實際上需要兩次獨立的Java呼叫。
因此,JDK 25 透過兩項新的 JEP 對此進行了改進。首先, JEP 514將 AOT 快取的建立簡化為一條指令。其次, JEP 515擴展了快取功能,使其能夠儲存方法執行設定文件,從而縮短應用程式的預熱時間。
本文將探討這兩個新的 JEP,並了解它們如何協同工作。要注意的是,我們需要 JDK 25 才能利用這些特性。
2. JDK 24 中 AOT 快取的工作原理
在深入探討 JDK 25 實作 AOT 快取的方法之前,讓我們先快速回顧一下 JDK 24 中 AOT 快取的工作原理。
當時要建立 AOT 緩存,我們需要呼叫兩次Java工具,從而建立兩個獨立的java進程。第一次呼叫以記錄模式運行應用程式。這意味著運行時會觀察應用程式在訓練運行期間的行為,並將該資訊儲存到 AOT 設定檔中:
$ java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -cp app.jar com.example.App
第二次呼叫使用上一個步驟產生的配置來實際建立快取:
$ java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot
最後,我們可以使用生成的快取運行應用程序,理論上,這應該可以顯著縮短啟動時間:
$ java -XX:AOTCache=app.aot -cp app.jar com.example.App
這種工作流程雖然可行,但會產生一個臨時設定文件,並且需要管理兩個不同的命令。經驗豐富的讀者可能會注意到,AppCDS 歸檔(實際上是 AOT 快取的前身)也採用了類似的繁瑣的兩階段流程。因此,JEP 514 專門針對 AOT 快取解決了這個問題。
3. 一次性 AOT 快取創建 (JEP 514)
JEP 514 引進了一個新的命令列非標準 ( -XX ) VM 選項: AOTCacheOutput 。當單獨使用此選項而不使用任何其他 AOT 標誌時,啟動器會自動將呼叫拆分為兩個內部子呼叫—一個用於訓練,一個用於建立快取。
因此,我們可以用以下方式取代上述兩步驟工作流程:
$ java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App
這條指令取代了原本用來建立 AOT 快取的兩個指令。 JVM 會將應用程式作為訓練練習運行,記錄其動態,然後一次建立 AOT 快取。
自 JDK 24 以來,生產命令(為生產工作負載提供快取)保持不變:
$ java -XX:AOTCache=app.aot -cp app.jar com.example.App
但關鍵在於──後台仍然執行著一個兩階段的過程。實際上, Java啟動器會建立兩個子進程來完成快取建立。這一點很重要,而且會產生影響。
4. 一次性方法的缺點
人們可能會認為雙進程設定是顯而易見的選擇,也是唯一正確的方法——但事實並非如此。
如前所述,這裡將啟動兩個distinct Java 進程,它們各自擁有獨立的堆疊記憶體。由於它們都由 Java 啟動器進程(即呼叫Java二進位檔案所建立的進程)啟動,因此峰值記憶體消耗可能會翻倍。所以,如果我們指定*`-Xmx4g`*參數,那麼單步驟工作流程最多可能需要 8GB 的堆記憶體才能完成。
因此,一步式工作流程適用於大多數場景,但兩步式方法也有其用武之地,尤其是在記憶體受限的環境中。例如,託管我們應用程式的雲端虛擬機器可能沒有足夠的記憶體資源來支援雙倍大小的堆記憶體。在這種情況下,顯式的兩步驟工作流程是更佳選擇。
5. AOT 方法分析 (JEP 515)
JEP 514 簡化了 AOT 快取的建立過程,而 JEP 515 則增強了快取儲存的資訊。
要理解 JEP 515,我們需要回顧 HotSpot 如何達到最佳效能。 JIT 編譯器會辨識出熱點方法(執行頻率相對較高的方法),然後將它們編譯成最佳化的本機程式碼。但為了做到這一點,它必須收集這些方法的效能分析資訊。而這個過程需要時間。通常,這段時間被稱為預熱期,在此期間,應用程式的運行速度會低於其潛在最佳效能。
坦白說,我們的應用程式執行模式通常大致相同。在相同情況下,我們的生產工作負載經常會執行類似的if分支。因此,每次應用程式啟動時,效能分析資訊都不會發生太大變化。所以,提前緩存這些資訊也是合理的。
因此,JEP 515 透過擴展 AOT 快取來解決這個問題,使其包含訓練運行中的方法執行概要檔。當應用程式在生產環境中啟動時,這些概要檔案可以立即使用,因此 JIT 編譯器可以立即開始產生最佳化程式碼,而無需等待預熱。
最棒的是,我們無需更改啟動命令,更不用說應用程式程式碼,即可利用此功能。效能分析資料會在訓練運行期間自動收集,然後儲存在 AOT 快取中。因此,它與 JEP 514 中的一步式工作流程完美相容,開箱即用:
# Training + cache creation (profiles are included automatically)
$ java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App
# Production run (benefits from both cached classes and cached profiling info)
$ java -XX:AOTCache=app.aot -cp app.jar com.example.App
在上述範例中,JVM 啟動時會使用已經包含某些效能分析資訊的程式碼快取。
6. 運行時分析與快取分析
需要特別注意的是,快取的效能分析結果並不會阻止生產環境中的後續效能分析。 HotSpot JVM 會在應用程式執行階段持續進行效能分析和最佳化,從而結合 AOT 分析、線上分析和 JIT 編譯的優勢。
這一點很重要,因為應用程式在生產環境中的行為仍然可能與訓練運行期間觀察到的情況有所不同。快取的設定檔可以幫助 JIT 快速啟動,使其能夠更快地編譯一些方法。隨著應用程式的運行,HotSpot 會重新評估其對工作負載模式的理解,並在需要時重新編譯方法。
7. 結論
JEP 514 和 JEP 515 都是OpenJDK 專案 Leyden的一部分,旨在提升 Java 的啟動和預熱效能。 JEP 514 帶來了一個實用的改進——將原本需要兩個步驟完成的 AOT 快取建立過程簡化為一條命令。雖然通常情況下,單步驟創建是更優的選擇,但在記憶體受限的環境中,兩階段創建過程可能是更合適的方案。
JEP 515 透過包含方法概要檔案來豐富快取數據,以便 JIT 編譯器可以從應用程式啟動之初就開始編譯。