默认的Java堆最大大小是如何确定的?

532
如果我在Java命令行中省略-Xmxn选项,则会使用默认值。根据Java文档,“默认值是根据系统配置在运行时选择的”。哪些系统配置设置影响默认值?

2
系统配置意味着:a)客户端JVM与服务器JVM b)32位与64位。链接:1)从J2SE5.0更新https://docs.oracle.com/javase/6/docs/technotes/guides/vm/gc-ergonomics.html 2)简要回答:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/ergonomics.html 3)详细回答:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/parallel.html#default_heap_size 4)客户端与服务器:https://www.javacodegeeks.com/2011/07/jvm-options-client-vs-server.html - Vyshnav Ramesh Thrissur
3
从上面的链接中很难理解,因此在这里对它们进行总结:客户端 JVM 的最大堆大小为 256MB(有一个例外,请从上面的链接中阅读)。32位服务器 JVM 的最大堆大小为1GB,64位服务器 JVM 的最大堆大小为32GB(同样也有例外情况,请从链接中了解)。因此,它可以是256MB、1GB或32GB。 - Vyshnav Ramesh Thrissur
1
请参见 https://dev59.com/M14c5IYBdhLWcg3wJnU-#56036202 - rogerdpack
10个回答

634

在Windows上,您可以使用以下命令查找应用程序运行的系统默认设置。

java -XX:+PrintFlagsFinal -version | findstr HeapSize

查找 MaxHeapSize (对应于 -Xmx)和 InitialHeapSize(对应于 -Xms)选项。

在 Unix/Linux 系统中,你可以执行:

java -XX:+PrintFlagsFinal -version | grep HeapSize

我相信最终的输出是以字节为单位的。


3
我本希望有一个像这样的好选择,但是在使用IBM的Java 6虚拟机时它对我不起作用。 - Matt Lavin
37
在我的Linux机器上,InitialHeapSize = 262803264MaxHeapSize = 4206886912,如果我没有弄错的话,这大约是256 MB4 GB。这是否意味着每个JVM都会像使用-Xms256m -Xmx4g选项一样启动? - Yuriy Nakonechnyy
11
在 Windows 系统上,运行以下命令:java -XX:+PrintFlagsFinal -version | findstr /R /C:"HeapSize" - sp00m
3
那么,0代表什么? :) - Ivan
3
@matanster 在我的Linux上,-version 命令会抑制 stderr 上的长“使用”文本。 - Franklin Yu
显示剩余5条评论

128

对于Java SE 5:根据垃圾回收器人体工程学 [Oracle]

初始堆大小:

机器物理内存的1/64或一些合理的最小值中较大的那个。在J2SE 5.0之前, 默认的初始堆大小是一个合理的最小值,这个值因平台而异。您可以使用-Xms命令行选项覆盖此默认值。

最大堆大小:

物理内存的1/4或1GB中较小的那个。在J2SE 5.0之前, 默认的最大堆大小为64MB。您可以使用-Xmx命令行选项覆盖此默认值。

更新:

正如Tom Anderson在他的评论中指出的那样,上述内容适用于服务器级别的机器。来自JavaTM虚拟机5.0中的人体工程学

在J2SE平台的5.0版本中,定义了一类称为服务器级别机器的机器,该机器具备以下特点:
  • 2个或更多物理处理器
  • 2GB或更多物理内存
除了运行Windows操作系统的32位平台之外,在所有其他平台上,默认值与1.4.2版本的默认值相同。 在J2SE平台的1.4.2版本中,默认选择如下:
  • 初始堆大小为4MB
  • 最大堆大小为64MB

4
注意:这是针对服务器级别的机器,而不是客户端级别。您需要结合http://java.sun.com/docs/hotspot/gc5.0/ergo5.html阅读该文档,该文档定义了这些术语以及客户端级别机器会发生什么情况。dogbane,我可以谦虚地建议您编辑您的答案以引用相关段落吗? - Tom Anderson
4
2012年64兆字节的默认值太低了。很少有严肃的应用程序能适应这个限制。 - Mark E. Haase
1
请参考Ernesto在2012年10月30日的回答,针对Java 6更新18之后的客户端机器。 - Andy Thomas
请注意,它说:“堆大小给出的边界和分数适用于J2SE 5.0。随着计算机变得更加强大,它们可能在后续版本中有所不同。” - PeterG
顺便提一下,这个算法仅适用于并行垃圾收集器。 - Mike Argyriou

77

Java 8会占用超过您物理内存的 1/64 作为您的 Xmssize(最小堆大小),并且不到物理内存的 1/4 作为您的 -Xmxsize(最大堆大小)。

您可以通过以下方式检查默认的Java堆大小

Windows中:

java -XX:+PrintFlagsFinal -version | findstr /i "HeapSize PermSize ThreadStackSize"

Linux中:

java -XX:+PrintFlagsFinal -version | grep -iE 'HeapSize|PermSize|ThreadStackSize'

哪些系统配置设置会影响默认值?

机器的物理内存和Java版本。


5
难道不是1/6,而是1/64吗? - Vyshnav Ramesh Thrissur
1
是的,Xmssize(最小堆大小/初始堆大小)大于物理内存的1/64,而Xmxsize(最大堆大小/最大堆大小)小于物理内存的1/4。(例如,对于我的Mac,有16GB RAM,我得到uintx InitialHeapSize:= 268435456 {product} uintx MaxHeapSize:= 4294967296 {product},即Xms为268 MB,Xmx为4.29 GB。) - sjethvani
这些值是以字节为单位的,如果你想要 MB,就除以 1024*1024。 - Jairo Martínez
这真的为我节省了很多时间,非常感谢 :) - Amit Meena
有没有办法将堆大小设置为物理内存的四分之一以上? - sendreams

43

这在Java 6更新18版中有所改变。

假设我们拥有超过 1 GB 的物理内存(现在相当普遍),服务器虚拟机的内存总是等于物理内存的四分之一。


10
链接页面上的说法是不正确的,它表示“物理内存大于等于1 GB 时,最大堆大小为256 MB”。 - Paolo Fulgoni
5
我刚在一台内存为5GB的Linux机器上检查了一下。默认的最大堆大小显示为1.5GB。 - ernesto
1
@PaoloFulgoni 不是,我现在观察到的另一个实际例子是:129 G字节的物理内存导致最大堆大小为32 G字节。 - Kirill
有关此情况的更多信息,请参见 https://dev59.com/1G445IYBdhLWcg3w3Nsf#13310792。另请参阅 https://dev59.com/M14c5IYBdhLWcg3wJnU-#56036202。 - rogerdpack
@PaoloFulgoni引用的部分是指“客户端”VM。@ernesto和@Kirill提供的示例可能是服务器VM,这是使用JDK VM而不是JRE时的默认配置。 - Emmanuel

35

终于!

自 Java 8u191 版本起,你现在可以选择:

-XX:InitialRAMPercentage
-XX:MaxRAMPercentage
-XX:MinRAMPercentage

可以用来将堆大小设置为可使用物理 RAM 的百分比。(与安装的 RAM 减去内核使用的 RAM 相同)。

有关更多信息,请参见 Java8 u191 发行说明。请注意,选项在 Docker 标题下提到,但实际上它们适用于您是在 Docker 环境还是传统环境中。

MaxRAMPercentage 的默认值为 25%。这非常保守。

我的建议是:如果您的主机或者服务器更多或更少是用于运行给定的 Java 应用程序,那么您可以毫不犹豫地大幅度增加堆大小。如果您正在 Linux 上运行标准守护程序,并且已经安装了约 1 GB 及以上的 RAM,则我会毫不犹豫地将 JVM 堆的大小设置为 75%。再次提醒,这是 RAM 可用内存的 75%,而不是 RAM 安装内存的 75%。留下的是可能在主机上运行的其他用户进程和 JVM 需要的其他类型的内存(例如堆栈)。所有这些内存加起来通常会完全适合剩下的 25%。当然,如果安装的 RAM 更多,则 75% 是一个更加安全的选择。 (我希望 JDK 的开发人员能够实现一种可以指定阶梯的选项)

设置 MaxRAMPercentage 选项如下:

java -XX:MaxRAMPercentage=75.0  ....

请注意,这些百分比值是“double”类型的,因此您必须使用十进制点来指定它们,否则如果您使用“75”而不是“75.0”,则会收到一些奇怪的错误提示。


1
似乎MinRAMPercentage参数与其名称不同,允许设置JVM运行时的最大堆大小内存较少(小于约250MB),而MaxRAMPercentage允许设置JVM运行时的最大堆大小内存较多(大于约250MB)。因此,默认值取决于RAM的数量。另一个值将被忽略。您可以使用docker run --rm openjdk:8 java -XX:+PrintFlagsFinal -version | grep -E "RAMPercentage"获取默认值。在我的笔记本电脑上,MaxRAMPercentage = 25.0MinRAMPercentage = 50% - Davide Madrisan
这些参数在“传统环境”中不起作用,我使用jdk8u333。 - sendreams
@sendreams:你记得在指定数值时使用小数点了吗? - peterh
@peterh 是的,我确实在使用,但是使用visualvm连接实例时,最大堆大小始终为16GB。 - sendreams
@peterh 这是一个 jsonsole 快照图像:https://1drv.ms/u/s!AkYceNl-teXvyzYGib13z62kW97U?e=G81xx7 - sendreams
@peterh 我犯了一个错误,现在它可以工作了。谢谢。 - sendreams

19

XmsXmx是Java虚拟机(JVM)的标志:

  • Xms堆内存初始大小
    • 格式-Xms<size>[g|G|m|M|k|K]
    • 默认大小
      • -server模式:空闲物理内存的25%,>=8MB且<=64MB
      • -client模式:空闲物理内存的25%,>=8MB且<=16MB
    • 典型大小
      • -Xms128M
      • -Xms256M
      • -Xms512M
    • 功能/效果
      • -> JVM启动时分配Xms大小的内存
  • XmxJVM堆内存最大值
    • 格式-Xmx<size>[g|G|m|M|k|K]
    • 默认大小
      • <= R27.2
        • Windows:总物理内存的75%,最高不超过1GB
        • Linux/Solaris:可用物理内存的50%,最高不超过1GB
      • >= R27.3
        • Windows X64:总物理内存的75%,最高不超过2GB
        • Linux/Solaris X64:可用物理内存的50%,最高不超过2GB
  • Windows x86: 可使用物理内存总量的 75%,最高可达 1GB
  • Linux/Solaris X86: 可使用可用物理内存的 50%,最高可达1GB
  • 通常大小
    • -Xmx1g
    • -Xmx2084M
    • -Xmx4g
    • -Xmx6g
    • -Xmx8g
  • 功能/效果:
    • -> JVM 允许使用最大 Xmx 大小的内存
      • 当超过 Xmx 时,会出现 java.lang.OutOfMemoryError
        • 如何解决 OutOfMemoryError
          • 超过 Xmx
            • 例如:从 -Xmx4g 增至 -Xmx8g
  • 更多详细信息

    请查看官方文档:-X 命令行选项


    1
    这不是针对JRockit JVM吗?(而不是Oracle的Hotspot JVM) - peterh

    16

    Ernesto正确。根据他发布的链接[1]:

    已更新客户端JVM堆配置

    在客户端JVM中...

    • 默认最大堆大小为物理内存的一半,最多可达192兆字节的物理内存大小,否则为物理内存的四分之一,最多可达1吉字节的物理内存大小。

      例如,如果您的机器有128兆字节的物理内存,则最大堆大小为64兆字节;如果大于等于1吉字节的物理内存,则最大堆大小为256兆字节。

    • JVM实际上不会使用最大堆大小,除非程序创建了足够多的对象需要它。在JVM初始化期间,分配了一个更小的初始堆大小。...

    • ...
    • 现在服务器JVM堆配置符合客户端JVM堆配置,只是32位JVM的默认最大堆大小为1吉字节,对应于4吉字节的物理内存大小;而64位JVM的默认最大堆大小为32吉字节,对应于128吉字节的物理内存大小。

    [1]http://www.oracle.com/technetwork/java/javase/6u18-142093.html


    10

    1
    链接似乎(实际上)已经失效。 - Peter Mortensen
    @PeterMortensen 刚刚检查了一下 - 链接没问题。 - Nik Handyman
    1
    @NikHandyman 现在出现了问题:很抱歉!未找到内容 - nikodaemus

    8

    根据系统配置,在运行时选择默认值。

    请查看文档page

    默认堆大小

    除非在命令行上指定了初始和最大堆大小,否则它们将基于计算机上的内存量进行计算。

    1. 客户端JVM默认初始和最大堆大小:

      默认最大堆大小为物理内存的一半(最大192兆字节),否则为物理内存的四分之一(最大1吉字节)。

    2. 服务器JVM默认初始和最大堆大小:

      在32位JVM上,如果有4GB或更多物理内存,则默认最大堆大小可以高达1GB。在64位JVM上,如果有128GB或更多物理内存,则默认最大堆大小可以高达32GB。

    哪些系统配置设置会影响默认值?

    您可以使用标志-Xms(初始堆大小)和-Xmx(最大堆大小)指定初始和最大堆大小。如果您知道应用程序需要多少堆才能正常工作,您可以将-Xms-Xmx设置为相同的值。


    6
    一些参数会影响生成大小。下图说明了堆中已提交空间和虚拟空间之间的差异。在虚拟机初始化时,整个堆的空间都被保留。可以使用 -Xmx 选项指定保留空间的大小。如果 -Xms 参数的值小于 -Xmx 参数的值,则并非立即将保留的所有空间都提交给虚拟机。此图中未提交的空间标记为“虚拟”。堆的不同部分(永久代、老年代和新生代)可以根据需要增长到虚拟空间的极限。

    enter image description here

    默认情况下,虚拟机在每次垃圾回收时增加或缩小堆以尝试保持空闲空间与活动对象之间的比例在特定范围内。此目标范围由参数 -XX:MinHeapFreeRatio=<minimum> 和 -XX:MaxHeapFreeRatio=<maximum> 以百分比设置,并且总大小在下限为 -Xms<min>,上限为 -Xmx<max>。
    参数 默认值
    MinHeapFreeRatio 40
    MaxHeapFreeRatio 70
    -Xms 3670k
    -Xmx 64m
    64位系统上堆大小参数的默认值已经扩大了约30%。这种增加是为了补偿64位系统上对象的更大尺寸。

    这些参数将使得如果某一代的可用空间百分比低于40%,则该代会被扩展以维持40%的可用空间,直到达到该代允许的最大大小。同样地,如果可用空间超过70%,则该代将被压缩,以便只有70%的空间是可用的,但必须满足该代的最小大小。

    大型服务器应用程序通常遇到这些默认值的两个问题。一个问题是启动速度慢,因为初始堆大小很小,需要在多次 major collections 中重新调整大小。更紧迫的问题是,对于大多数服务器应用程序来说,默认的最大堆大小太小了。服务器应用程序的经验法则是:

    • 除非您遇到暂停问题,否则尝试为虚拟机授予尽可能多的内存。默认大小(64MB)通常太小。
    • 将-Xms和-Xmx设置为相同的值可以通过从虚拟机中删除最重要的调整决策来增加可预测性。然而,如果您做出了错误的选择,则虚拟机将无法进行补偿。
    • 通常情况下,随着处理器数量的增加,增加内存,因为分配可以并行化。

      这里有完整文章


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