环境变量 JDK_JAVA_OPTIONS 与 JAVA_TOOL_OPTIONS 之间有什么区别?
1、概览
在配置 Java 应用时,我们经常需要在不修改脚本的情况下传递 JVM 选项。
我们可以使用环境变量 JDK_JAVA_OPTIONS
或 JAVA_TOOL_OPTIONS
,而不是每次运行 java
命令时都手动添加标记。这两个环境变量的作用相同:动态传递 JVM 选项,但它们的工作方式不同。
本文将带你了解它们的区别、何时使用每种配置以及有效管理 JVM 配置的最佳实践。
2、JDK_JAVA_OPTIONS 和 JAVA_TOOL_OPTIONS 是什么?
这两个环境变量都允许我们在全局范围内指定 JVM 选项,从而省去了每次执行 JDK 工具(如 java
、javac
、javadoc
等)时修改选项的麻烦。
JAVA_TOOL_OPTIONS
在 Java 5 中引入。它们的行为和目的截然不同。
在深入了解每个环境变量的功能之前,先创建一个简单的 Java 源码文件:
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") + "'");
}
}
上面的代码非常简单。我们的 main()
方法会打印出 var1
和 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
命令。
首先,在 JDK_JAVA_OPTIONS
中定义 var1
和 var2
,然后启动 main()
方法:
$ 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
变量,并将 var1
和 var2
的值传递给了 main()
方法,产生了预期的结果。此外,java 还输出了一条信息,告知我们 JDK_JAVA_OPTIONS
已被读取。
需要注意的是,我们在同一行设置了环境变量并执行了 java
命令,中间用空格隔开。这就确保了 JDK_JAVA_OPTIONS
只为特定的 java
命令设置。如果我们在运行命令后检查该变量,就会发现 JDK_JAVA_OPTIONS
不再有值:
$ echo $JDK_JAVA_OPTIONS
现在,让我们在 JAVA_TOOL_OPTIONS
中设置 var1
和 var2
,然后运行类:
$ 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
变量也会影响 Java Launcher(启动器)。此外,类似的信息还告诉我们 java
命令读取了 JAVA_TOOL_OPTIONS
。
现在,有人可能会问:如果在 JDK_JAVA_OPTIONS
和 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)'
在本例中,我们在 JAVA_TOOL_OPTIONS
中定义了 var1
和 var2
,但只在 JDK_JAVA_OPTIONS
中用不同的值定义了 var2
。输出结果显示,java 获取了这两个环境变量。但如果在 JDK_JAVA_OPTIONS
和 JAVA_TOOL_OPTIONS
中设置了相同的变量,则 JDK_JAVA_OPTIONS
优先。
4、其他 Java 命令
除了 java
命令外,JDK 还提供了其他一些命令,使我们能够高效地编译、记录和管理 Java 应用,例如
- javac - Java 编译器
- javadoc - JavaDoc 生成器
- 等…
接下来,让我们弄清楚这些工具如何处理 JDK_JAVA_OPTIONS
和 JAVA_TOOL_OPTIONS
。
我们以 javac
编译器为例。与 java 命令不同,通过 javac
检查变量值并不直接。因此,为了测试其行为,我们将在 JDK_JAVA_OPTIONS
和 JAVA_TOOL_OPTIONS
中设置最大堆大小 (-Xmx
) JVM 参数,并验证它是否会如预期般影响 javac
。
首先,检查一下 javac
默认的 MaxHeapSize
值:
$ javac -J-XX:+PrintCommandLineFlags com/baeldung/TestEnvVar.java
... -XX:MaxHeapSize=9663676416 ...
在本例中,-J-XX:+PrintCommandLineFlags
选项用于某些 JDK 工具(本例中为 javac
),以在工具启动时打印出 JVM 正在使用的命令行标志。
如输出所示,在这台机器上,JVM 默认将 9GiB (9102410241024=9663676416 字节) 内存作为 MaxHeapSize
。接下来,让我们在 JAVA_TOOL_OPTIONS
中设置 10MiB(1010241024 = 10485760 字节)为 MaxHeapSize
,然后再次编译源文件:
$ JAVA_TOOL_OPTIONS="-Xmx10m" javac -J-XX:+PrintCommandLineFlags com/baeldung/TestEnvVar.java
Picked up JAVA_TOOL_OPTIONS: -Xmx10m
... -XX:MaxHeapSize=10485760 ...
如输出所示,JAVA_TOOL_OPTIONS
会影响 javac。
接下来,对 JDK_JAVA_OPTIONS
变量进行同样的测试:
$ JDK_JAVA_OPTIONS="-Xmx10m" javac -J-XX:+PrintCommandLineFlags com/baeldung/TestEnvVar.java
... -XX:MaxHeapSize=9663676416 ...
原来 JDK_JAVA_OPTIONS
并不影响 javac
。它仍然使用默认选项编译源文件: MaxHeapSize=9GiB.
实际上,这不仅仅是 javac
的问题。它适用于除 java
命令之外的所有 JDK 工具 - 只有 JAVA_TOOL_OPTIONS
才能被识别。
接下来,使用 JDK 的另一个工具 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 ...
可以看到,该命令忽略了 JDK_JAVA_OPTIONS
中设置的 -Xmx10m
参数,但正确识别了 JAVA_TOOL_OPTIONS
变量中的值。
5、JDK_JAVA_OPTIONS 和 JAVA_TOOL_OPTIONS
了解了这两个环境变量如何与 JDK 工具配合使用后来总结一下它们的区别:
对比面 | JAVA_TOOL_OPTIONS | JDK_JAVA_OPTIONS |
---|---|---|
目的 | 用于将 JVM 选项和参数传递给 JDK 工具的环境变量 | 环境变量,用于将 JVM 选项和参数传递给 Java Launcher 以启动 Java 应用 |
范围 | 它会影响所有 JDK 工具(java 、javac 、javadoc 、jar 等)。 |
它只影响 java 命令 |
版本限制 | Java 5+ | Java 9+ |
Java Launcher 的优先级 | JDK_JAVA_OPTIONS 中的值会覆盖此变量中设置的相同选项 |
优先 |
由于 JDK_JAVA_OPTIONS
环境变量是在 Java 9 中引入的,并且是 java
命令的专属变量,因此在 Java 9 或更高版本上设置启动应用程序的选项时应使用该变量。但是,如果我们需要在 JDK 工具中全局设置选项,则应选择 JAVA_TOOL_OPTIONS
。
6、总结
本文通过实际示例介绍了环境变量 JDK_JAVA_OPTIONS
和 JAVA_TOOL_OPTIONS
之间的区别,以及应该在何时使用哪个变量。
Ref:https://www.baeldung.com/java-jdk_java_options-vs-java_tool_options