1. 概述

配置 Java 应用时,我们经常需要在不修改启动脚本的情况下传递 JVM 选项。与其每次手动在 java 命令中添加参数,不如使用环境变量 JDK_JAVA_OPTIONSJAVA_TOOL_OPTIONS。这两个环境变量都能动态传递 JVM 选项,但工作机制截然不同。

本文将通过实际示例对比它们的差异,帮你搞清楚何时该用哪个,以及高效管理 JVM 配置的最佳实践。

2. 什么是 JDK_JAVA_OPTIONS 和 JAVA_TOOL_OPTIONS?

这两个环境变量都能全局指定 JVM 选项,避免每次执行 javajavacjavadoc 等 JDK 工具时重复配置。

  • JAVA_TOOL_OPTIONS:Java 5 引入的老牌选手
  • JDK_JAVA_OPTIONS:Java 9 推出的新贵

先创建一个测试类:

package com.baeldung;
/**
 * 打印环境变量值的简单类
 */
public class TestEnvVar {

    public static void main (String[] args){
        System.out.println("var1 = '" + System.getProperty("var1") + "'");
        System.out.println("var2 = '" + System.getProperty("var2") + "'");
    }

}

编译代码:

$ javac com/baeldung/TestEnvVar.java

文件结构:

$ tree
.
└── com
    └── baeldung
        ├── TestEnvVar.class
        └── TestEnvVar.java

3 directories, 1 file

本文所有示例基于 Java 23(Linux 环境):

$ java -version
openjdk version "23.0.1" 2024-10-15
OpenJDK Runtime Environment Homebrew (build 23.0.1)
OpenJDK 64-Bit Server VM Homebrew (build 23.0.1, mixed mode, sharing)

3. 执行 Java 启动器——java 命令

最典型的 Java 程序启动方式是使用 java 命令。先通过 JDK_JAVA_OPTIONS 传递参数:

$ JDK_JAVA_OPTIONS="-Dvar1='Hello (JDK_JAVA_OPTIONS)' -Dvar2='World (JDK_JAVA_OPTIONS)'" java com.baeldung.TestEnvVar
NOTE: Picked up JDK_JAVA_OPTIONS: -Dvar1='Hello (JDK_JAVA_OPTIONS)' -Dvar2='World (JDK_JAVA_OPTIONS)'
var1 = 'Hello (JDK_JAVA_OPTIONS)'
var2 = 'World (JDK_JAVA_OPTIONS)'

关键点:

  • java 命令会读取 JDK_JAVA_OPTIONS
  • ✅ 输出中明确提示已拾取该变量
  • ⚠️ 注意:环境变量和命令在同一行执行,确保仅对本次命令生效

执行后检查变量值:

$ echo $JDK_JAVA_OPTIONS
   

再测试 JAVA_TOOL_OPTIONS

$ JAVA_TOOL_OPTIONS="-Dvar1='Hi (JAVA_TOOL_OPTIONS)' -Dvar2='There (JAVA_TOOL_OPTIONS)'" java com.baeldung.TestEnvVar
Picked up JAVA_TOOL_OPTIONS: -Dvar1='Hi (JAVA_TOOL_OPTIONS)' -Dvar2='There (JAVA_TOOL_OPTIONS)'
var1 = 'Hi (JAVA_TOOL_OPTIONS)'
var2 = 'There (JAVA_TOOL_OPTIONS)'

同样生效,但输出提示不同。现在测试冲突场景——当两个变量同时存在时:

$ JAVA_TOOL_OPTIONS="-Dvar1='Hi (JAVA_TOOL_OPTIONS)' -Dvar2='There (JAVA_TOOL_OPTIONS)'" JDK_JAVA_OPTIONS="-Dvar2='World (by JDK_JAVA_OPTIONS)'" java com.baeldung.TestEnvVar
NOTE: Picked up JDK_JAVA_OPTIONS: -Dvar2='World (by JDK_JAVA_OPTIONS)'
Picked up JAVA_TOOL_OPTIONS: -Dvar1='Hi (JAVA_TOOL_OPTIONS)' -Dvar2='There (JAVA_TOOL_OPTIONS)'
var1 = 'Hi (JAVA_TOOL_OPTIONS)'
var2 = 'World (by JDK_JAVA_OPTIONS)'

结论:

  • ✅ 两个变量都会被读取
  • 冲突时 JDK_JAVA_OPTIONS 优先级更高var2 的值被覆盖)

4. 其他 Java 命令

除了 java,JDK 还提供 javacjavadoc 等工具。它们如何处理这两个变量?以 javac 为例:

先查看默认堆内存(MaxHeapSize):

$ javac -J-XX:+PrintCommandLineFlags com/baeldung/TestEnvVar.java
... -XX:MaxHeapSize=9663676416 ...

默认值约 9GiB。通过 JAVA_TOOL_OPTIONS 限制为 10MiB:

$ JAVA_TOOL_OPTIONS="-Xmx10m" javac -J-XX:+PrintCommandLineFlags com/baeldung/TestEnvVar.java
Picked up JAVA_TOOL_OPTIONS: -Xmx10m
... -XX:MaxHeapSize=10485760 ...

✅ 生效!堆内存被限制为 10MiB。再用 JDK_JAVA_OPTIONS 测试:

$ JDK_JAVA_OPTIONS="-Xmx10m" javac -J-XX:+PrintCommandLineFlags com/baeldung/TestEnvVar.java
... -XX:MaxHeapSize=9663676416 ...

无效! 仍使用默认值 9GiB。这并非 javac 特例——**除 java 命令外,所有 JDK 工具只识别 JAVA_TOOL_OPTIONS**。

javadoc 验证:

$ JAVA_TOOL_OPTIONS="-Xmx10m" javadoc -J-XX:+PrintCommandLineFlags com/baeldung/TestEnvVar.java
Picked up JAVA_TOOL_OPTIONS: -Xmx10m
... -XX:MaxHeapSize=10485760 ...

$ JDK_JAVA_OPTIONS="-Xmx10m" javadoc -J-XX:+PrintCommandLineFlags com/baeldung/TestEnvVar.java | sed 's/ /\n/g' | grep MaxHeapSize
Loading source file com/baeldung/TestEnvVar.java...
... -XX:MaxHeapSize=9663676416 ...

结果一致:JAVA_TOOL_OPTIONS 生效,JDK_JAVA_OPTIONS 被忽略。

5. JDK_JAVA_OPTIONS vs. JAVA_TOOL_OPTIONS

总结核心差异:

特性 JAVA_TOOL_OPTIONS JDK_JAVA_OPTIONS
用途 为所有 JDK 工具传递 JVM 选项 仅给 Java 启动器传递选项
作用范围 所有 JDK 工具 (java/javac/javadoc等) java 命令
支持版本 Java 5+ Java 9+
优先级 冲突时被 JDK_JAVA_OPTIONS 覆盖 更高优先级

使用建议:

  • Java 9+ 启动应用 → 优先用 JDK_JAVA_OPTIONS
  • 全局配置所有 JDK 工具 → 只能用 JAVA_TOOL_OPTIONS
  • ⚠️ 避免同时设置冲突参数,优先级问题可能导致配置失效

6. 总结

通过实际测试,我们明确了两个关键差异:

  1. 作用域不同JAVA_TOOL_OPTIONS 影响所有 JDK 工具,JDK_JAVA_OPTIONS 仅作用于 java 命令
  2. 优先级不同:在 java 命令中,JDK_JAVA_OPTIONS 的配置会覆盖 JAVA_TOOL_OPTIONS

合理使用这两个变量,可以:

  • 避免重复配置 JVM 参数
  • 灵活控制不同工具的运行时行为
  • 减少因手动修改脚本导致的踩坑风险

下次需要动态传递 JVM 选项时,根据场景选择合适的变量,配置管理将变得简单高效!


原始标题:What Is the Difference Between JDK_JAVA_OPTIONS and JAVA_TOOL_OPTIONS? | Baeldung