JVM 中的參數前綴
1.概述
Java 虛擬機器 (JVM) 是一個為 Java 應用程式提供動力的強大引擎。它執行已編譯的.class
文件,管理內存,並使用即時 (JIT) 編譯和垃圾收集等技術來提高效能。
JVM 非常靈活。透過正確的參數,我們可以調整其行為以提高效能、解決問題並輕鬆嘗試實驗性功能。在本教學中,我們將探討可用於設定 JVM 的不同參數前綴。
2.什麼是 JVM 參數?
JVM 參數是可以改變 JVM 行為的特殊命令列選項。這些參數控制記憶體設定、效能調整、啟用調試和監控、垃圾收集配置和實驗功能等。
我們可以在啟動JVM時指定這些參數,例如:
java -Xmx512m -Denv=prod -verbose:gc -XX:+UseG1GC -jar App.jar
在上面的指令中,我們使用了多個不同的前綴。每個前綴都會告訴 JVM 正在傳遞什麼類型的配置。
-
-Xmx512m
– 將最大堆大小設定為 512 MB。 (非標準選項) -
-Denv=prod
– 定義一個名為env
且值為 prod 的系統屬性。 (系統屬性) -
-verbose:gc
– 啟用垃圾收集日誌記錄。 (標準選項) -
-XX:+UseG1GC
– 告訴 JVM 使用 G1 垃圾收集器。 (進階選項)
讓我們詳細探討每個前綴。
3. 不同的 JVM 參數前綴
3.1.系統屬性( -D
)
系統屬性通常用於配置 JVM 特定的參數,例如檔案編碼、使用者目錄、JVM 版本和其他 Java 特定的配置。
我們可以透過使用-D
命令列參數傳遞鍵值對(稱為系統屬性)來定義它們,如下所示:
java -Denv=prod -jar App.jar
在-D
參數前綴中,字母 D 代表 Define。 Java 沒有使用其他字母以避免混淆。它簡短、簡單、易於記憶。它告訴我們正在定義一個屬性。
3.2.標準選項 ( –
)
Java 標準選項是記錄的設置,我們可以將其與任何 JVM 一起使用來控制其基本行為。所有 JVM 實作都支援標準選項。這些選項可幫助我們管理 JVM 如何啟動和執行 Java 程式。
例如,我們可以使用-classpath
來設定類別路徑,使用-version
來檢查 JVM 版本:
java -version
它列印:
openjdk version "17.0.14" 2025-01-21 LTS
OpenJDK Runtime Environment Corretto-17.0.14.7.1 (build 17.0.14+7-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.14.7.1 (build 17.0.14+7-LTS, mixed mode, sharing)
我們可以在終端機中執行java
命令來查看標準選項清單:
Usage: java [options] <mainclass> [args...]
(to execute a class)
or java [options] -jar <jarfile> [args...]
(to execute a jar file)
where options include:
-cp <class search path of directories and zip/jar files>
-classpath <class search path of directories and zip/jar files>
--class-path <class search path of directories and zip/jar files>
A : separated list of directories, JAR archives,
and ZIP archives to search for class files.
To specify an argument for a long option, you can use --<name>=<value> or
--<name> <value>.
3.3.非標準選項( -X
)
我們使用-X
選項來存取通常控制記憶體和偵錯行為的非標準 JVM 功能。這些選項在不同的 JVM 實作(如 OpenJDK、HotSpot 或 Microsoft 的 JVM)中會有所不同。例如,Red Hat 的 JVM 可能支援與 Microsoft 不同的-X
選項。
我們可以使用以下命令列出所有非標準選項:
java -X
輸出將取決於 JVM 實作:
-Xbatch disable background compilation
-Xbootclasspath/a:<directories and zip/jar files separated by :>
append to end of bootstrap class path
-Xcheck:jni perform additional checks for JNI functions
-Xcomp forces compilation of methods on first invocation
-Xdebug does nothing. Provided for backward compatibility.
[...]
這些選項對於通用調整很有用,但我們應該謹慎使用它們,因為它們是特定於實現的,並且可能會更改,恕不另行通知。
3.4.進階選項( -XX
)
我們可以使用進階 JVM 選項來啟用低階、通常是實驗性的功能。這些選項以-XX.
我們可以將這些選項分為兩種類型:布林選項(允許我們啟用或停用特定功能)和值選項(允許我們設定自訂值)。
其中一些選項在各個版本中保持穩定,但其他選項可能會變更、被棄用,甚至在未來的 JVM 版本中被刪除。由於並非所有 JVM 實作都支援每個進階選項,因此我們必須謹慎使用它們並隨著 JVM 的發展保持更新。
讓我們來看看使用進階選項來調整 JVM 的垃圾收集行為以獲得更好的回應能力的命令:
java -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar App.jar
在這裡,我們首先指示 JVM 使用 G1 垃圾收集器,然後要求它將 GC 暫停時間控制在 200 毫秒以下。這是一個軟目標,意味著 JVM 將嘗試滿足它,但不保證它。
4. JVM執行模式
讓我們來看看可以用來控制 JIT 編譯的不同 JVM 執行模式,它在執行時間將 Java 位元組碼編譯為本機機器碼,並根據執行時間分析對其進行最佳化。
我們將使用Benchmark.java
程序,該程序以 100 萬個鍵值對填充HashMap
並檢索所有值以確保正確性並衡量效能。
public class Benchmark {
private static final int NUM_ENTRIES = 1_000_000;
public static void main(String[] args) {
Benchmark benchmark = new Benchmark();
benchmark.run();
}
public void run() {
HashMap<Integer, String> map = new HashMap<>();
// Fill the HashMap
long startPut = System.nanoTime();
for (int i = 0; i < NUM_ENTRIES; i++) {
map.put(i, "Value" + i);
}
long endPut = System.nanoTime();
System.out.println("Time to put: " + (endPut - startPut) / 1_000_000 + " ms");
// Retrieve from the HashMap
long startGet = System.nanoTime();
for (int i = 0; i < NUM_ENTRIES; i++) {
String value = map.get(i);
if (value == null) {
System.err.println("Missing key: " + i);
}
}
long endGet = System.nanoTime();
System.out.println("Time to get: " + (endGet - startGet) / 1_000_000 + " ms");
}
}
4.1. -Xint
– 僅限解釋模式
-Xint
標誌強制 JVM 解釋所有字節碼而不是編譯它。這將完全禁用 JIT 編譯。結果,執行速度嚴重減慢。
此標誌可協助我們在偵錯期間隔離與 JIT 行為相關的問題,並比較 JIT 編譯與純解釋對效能的影響。
我們來看看解釋執行模式的表現:
java -server -showversion -Xint Benchmark
openjdk version "17.0.14" 2025-01-21 LTS
OpenJDK Runtime Environment Corretto-17.0.14.7.1 (build 17.0.14+7-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.14.7.1 (build 17.0.14+7-LTS, interpreted mode, sharing)
Time to put: 1532 ms
Time to get: 261 ms
4.2. -Xcomp –
僅編譯模式
-Xcomp
標誌強制 JVM 在首次使用時編譯所有方法,而不是等待識別熱方法。這聽起來不錯,因為它完全避免了緩慢的解釋器。
然而,儘管它可能帶來長期的效能提升,但由於激進的編譯,它通常會導致啟動速度變慢。
我們來看看編譯執行模式的表現:
java -server -showversion -Xcomp Benchmark
openjdk version "17.0.14" 2025-01-21 LTS
OpenJDK Runtime Environment Corretto-17.0.14.7.1 (build 17.0.14+7-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.14.7.1 (build 17.0.14+7-LTS, compiled mode, sharing)
Time to put: 1167 ms
Time to get: 10 ms
4.3. -Xmixed –
預設模式
混合模式首先解釋程式碼,然後使用 JIT 編譯器編譯熱門方法。這種方法幫助我們平衡啟動時間和長期效能,讓我們兩全其美。
HotSpot 的最新版本預設使用混合模式,因此我們不再需要手動指定此標誌。讓我們來看看它的表現:
java -server -showversion Benchmark
openjdk version "17.0.14" 2025-01-21 LTS
OpenJDK Runtime Environment Corretto-17.0.14.7.1 (build 17.0.14+7-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.14.7.1 (build 17.0.14+7-LTS, mixed mode, sharing)
Time to put: 75 ms
Time to get: 12 ms
輸出顯示預設混合模式在啟動時間和運行時效能之間提供了最佳平衡。解釋模式-Xint
明顯較慢,主要用於調試或分析。編譯模式-Xcomp
減少了熱路徑的執行時間,但啟動成本較高。
4.4. -Xverify –
驗證控制
當 Java 程式碼被編譯時,它會變成字節碼,由 JVM 執行。 JVM 在執行之前會進行字節碼驗證,以確保程式碼符合 JVM 規格、正確使用堆疊、安全地存取變數並維護正確的控制流程。此步驟有助於防止崩潰和安全風險,特別是在執行不受信任或第三方程式碼時。
-Xverify
選項允許我們控製字節碼驗證何時發生以及是否發生。 -Xverify:all
選項是預設行為。當 JVM 載入所有類別時,它會驗證它們。這確保了執行過程中的安全性和正確性。
-Xverify:none
選項在載入期間跳過類別驗證。它可能會稍微改善啟動時間,但會降低安全性並且可能存在風險:
java -Xverify:none -cp app.jar com.baeldung.Main
我們可以使用 VisualVM 和 Java 管理擴充 (JMX) 對 Java 應用程式進行遠端監控。
5. 結論
在本教程中,我們探討了各種 JVM 參數前綴。 JVM 執行模式也屬於非標準參數前綴。混合模式為一般應用程式提供了最有效和最穩定的行為。使用正確的JVM 參數可以**增強應用程式的效能、提高穩定性並簡化調試**。
設定特定 JVM 參數的決定取決於幾個因素,包括應用程式的複雜性及其效能要求。使用常用的 JVM 參數可以增強我們應用程式的效能和功能。