重复的Java运行时选项:优先顺序是什么?

99

考虑以下命令行

java -Xms128m -Xms256m myapp.jar

JVM最小内存设置(Xms选项)会应用哪个值:128m还是256m?


22
请注意,原问题中没有拼写错误。 Xms选项是故意使用两次的。这是问题的实质。 - fabien7474
7个回答

71

一如既往,要检查您本地JVM的具体实现,但这里有一个快速的方法可以在命令行上检查,而无需编写代码。

> java -version; java -Xmx1G -XX:+PrintFlagsFinal -Xmx2G 2>/dev/null | grep MaxHeapSize

java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
uintx MaxHeapSize         := 2147483648        {product}

所以在这种情况下,参数的第二个实例(2G)优先考虑(至少在1.8版本中是如此),我在大多数其他现代版本中也有相同的经验。


9
使用命令java -Xmx1G -XX:+PrintFlagsFinal -Xmx2G 2>/dev/null | grep MaxHeapSize能够更轻松地推断出最大堆大小。该命令会打印Java虚拟机的配置信息,其中包括最大堆大小的信息,并使用grep命令筛选出包含"MaxHeapSize"关键词的行。 - ryenus

41

IBM JVM将参数列表中最右边的实例视为优先。关于HotSpot等其他JVM,我无法发表评论。

我们这样做是因为通常会有来自批处理文件的嵌套命令行,人们只能在末尾添加,并希望使其成为优先。


28
对于实际回答问题而非空谈的做法点个赞。 - JimN
Indeed: https://www.ibm.com/support/knowledgecenter/SSYKE2_7.0.0/com.ibm.java.zos.70.doc/diag/appendixes/cmdline/cmdline_specifying.html - Jorge Poveda

39

顺便说一句,OpenJDK 1.7看起来也是采取最右边的值,至少对于-Xms参数是这样。


16
将英语翻译成中文。仅返回翻译的文本内容:回答问题得+1,而不是卖弄。 - JimN
1
就像 CSS 一样,后者胜出。 - ryenus

32

取决于JVM,也许还取决于版本...甚至也可能取决于您桌子上有多少回形针。 它可能根本无法工作。 不要这样做。

如果出于某些原因超出了您的控制,请按照启动jar包的方式编译和运行此程序。但是请注意,依赖选项顺序是一个非常糟糕的主意。

public class TotalMemory
{
    public static void main(String[] args)
    {
         System.out.println("Total Memory: "+Runtime.getRuntime().totalMemory());
         System.out.println("Free Memory: "+Runtime.getRuntime().freeMemory());
    }
}

2
+1 - 最好数一下那些回形针 :-). 说真的,更改传递这些模棱两可的参数并不是什么难事。 - Stephen C
4
一直尝试着用不同数量的纸片,但找不到切换到第一个的开关。 - OganM

17

JVM最小内存应该设置哪些参数?

在下面列出的各种Java版本中,参数列表中最右边的值将被视为“获胜者”。正如其他人所指出的那样,依赖此方法可能不是一个好主意,但也许这些信息仍然是有用的。

Java 1.8.0_172

~ $ java8
java version "1.8.0_172"
Java(TM) SE Runtime Environment (build 1.8.0_172-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)
~ $ java -Xmx1024m -Xmx4024m -XX:+PrintFlagsFinal Test 2>/dev/null | grep MaxHeapSize
    uintx MaxHeapSize                              := 4219469824                          {product}

Java 11.0.3

~ $ java11
java version "11.0.3" 2019-04-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.3+12-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.3+12-LTS, mixed mode)
~ $ java -Xmx1024m -Xmx4024m -XX:+PrintFlagsFinal Test 2>/dev/null | grep MaxHeapSize
   size_t MaxHeapSize                              = 4219469824                                {product} {command line}

OpenJDK 12.0.1

~ $ java12
openjdk version "12.0.1" 2019-04-16
OpenJDK Runtime Environment (build 12.0.1+12)
OpenJDK 64-Bit Server VM (build 12.0.1+12, mixed mode, sharing)
~ $ java -Xmx1024m -Xmx4024m -XX:+PrintFlagsFinal Test 2>/dev/null | grep MaxHeapSize
   size_t MaxHeapSize                              = 4219469824                                {product} {command line}

AdoptOpenJDK 12.0.1

~ $ java12a
openjdk version "12.0.1" 2019-04-16
OpenJDK Runtime Environment AdoptOpenJDK (build 12.0.1+12)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 12.0.1+12, mixed mode, sharing)
~ $ java -Xmx1024m -Xmx4024m -XX:+PrintFlagsFinal Test 2>/dev/null | grep MaxHeapSize
   size_t MaxHeapSize                              = 4219469824                                {product} {command line}

OpenJDK 13-ea

:这是OpenJDK项目的一个版本,编号为13-ea。
~ $ java13
openjdk version "13-ea" 2019-09-17
OpenJDK Runtime Environment (build 13-ea+22)
OpenJDK 64-Bit Server VM (build 13-ea+22, mixed mode, sharing)
~ $ java -Xmx1024m -Xmx4024m -XX:+PrintFlagsFinal Test 2>/dev/null | grep MaxHeapSize
   size_t MaxHeapSize                              = 4219469824                                {product} {command line}

这种行为在Java SE 11.0.14(构建11.0.14+8-LTS-263)以及OpenJDK 17.0.1(构建17.0.1+12-39)中保持一致。 - Kaan

10

我打赌是第二个。通常情况下,参数的处理顺序如下:

for( int i=0; i<argc; i++ ) {
  process_argument(argv[i]);
}

不过,如果我正在编写 Java 参数解析器,我会抱怨冲突的参数。


0

我的实验表明它取最大值xmx

因此,如果你传入-xmx4g -xmx1g,它将取4g, 如果你传入-xmx1g -xmx4g,它仍然会取4g


1
我在AdoptOpenJDK-11.0.11+9中没有看到这种行为,使用java -version; java -Xmx2G -Xmx1G -XX:+PrintFlagsFinal 2>/dev/null | grep MaxHeapSize - Adrian Baker
我会鼓励更多、不同的实验。我的个人实验(在相同问题的另一个答案中有详细描述)表明,在Java SE 1.8.0、11.0.3、11.0.14版本以及OpenJDK 12.0.1、13和17.0.1版本中,最大值并未被使用,而是使用了最右边的值。 - Kaan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接