【问题标题】:-Xmx attribute and available system memory correlation-Xmx 属性与可用系统内存相关
【发布时间】:2026-01-09 00:50:01
【问题描述】:

我有一个问题。假设我有两个参数传递给 JVM: -Xms256mb -Xmx1024mb 在程序开始时分配了 256MB。接下来,创建一些对象,JVM 进程尝试分配更多内存。假设 JVM 需要分配 800MB。 Xmx 属性允许这样做,但系统上当前可用的内存(比如说 Linux/Windows)是 600MB。是否有可能抛出 OutOfMemoryError ?或者交换机制会起作用?

我的第二个问题与 GC 算法的质量有关。假设我有 jdk1.5u7 和 jdk1.5u22。是否有可能在后一个 JVM 中内存泄漏消失并且 OutOfMemoryError 不会发生?最新版本的GC质量能更好吗?

【问题讨论】:

  • 不管 GC 在以后的版本中是否更好,如果你将它推到如此接近内存不足错误的地步,你不能依赖 GC 来可靠地清理它...您需要分配更多内存。
  • 我注意到 jdk1.5u7 (Linux) 因 OutOfMemoryError 而崩溃,而 jdk1.5u17 (Windows) 仍然存在。使用相同的代码和属性。
  • 你的linux机器有swap吗?

标签: java memory memory-management memory-leaks garbage-collection


【解决方案1】:

关于您的第一个问题:
实际上,如果机器无法分配您要求的1024 MB 作为最大堆大小,它甚至不会启动 JVM。
我知道这一点是因为我注意到它经常试图打开具有大堆大小的 Eclipse,并且操作系统无法分配 JVM 无法加载的更大堆空间。您也可以自己尝试确认。所以其余的细节与你无关。当然,如果您的程序使用太多交换(与所有语言相同),那么性能将非常糟糕。

关于你的第二个问题:

内存泄漏消失了

不可能,因为它们是错误必须修复

并且 OutOfMemoryError 不会发生? GC的质量能不能更好 在最新版本中?

这可能发生,例如,如果在 GC 中使用了一些不同的算法,并且它设法在您看到异常之前启动。但是,如果您有内存泄漏,那么它可能会掩盖它,或者您会看到它断断续续。
各种 JVM 也有不同的 GC,你可以配置

更新:
我不得不承认(在看到@Orochi 注释之后)我注意到 Windows 上最大堆的行为。我不能肯定地说这也适用于 linux。不过你可以自己试试。

更新 2: 作为对@DennisCheung cmets 的回答 来自IBM(我的重点):

该表显示了可能的最大 Java 堆和最大 Java 堆大小设置的推荐限制......拥有比所有所需更多的物理内存很重要机器上的进程结合起来防止分页或交换。分页会降低系统性能,影响 Java 内存管理系统的性能。

【讨论】:

  • JVM 会在启动虚拟机之前验证您的参数,Xmx 对操作系统和虚拟机版本的限制很少。但与当前内存分配状态无关。
  • @DennisCheung:不确定您所说的限制是什么意思。在 4GB RAM 的 Windows 中,我注意到如果无法分配请求的最大堆,则 JVM 不会启动
  • Sun/Oracle JVM 对 Xmx 有硬核限制。对于 Windows,它应该是 1000M、1024M 或 2048MB,具体取决于版本。查看他们的文档以获取详细信息。我手头没有链接,因为他们不断更改他们的网站。
  • @DennisCheung:我不相信有一个。他们是推荐的,例如IBM 建议 32 位系统上的 JVM 不超过 1.5GB,但该建议只是因为 java 堆大小设置越高,您拥有的本机内存越少,因此在线程创建期间您仍然可能最终出现 OOM,permgen等等。但据我所知,实际数字集没有其他限制。如果您有参考资料,我很乐意知道。
  • @DennisCheung:而且你所说的并没有让我的答案出错,因为最终结果是相同的。无法设置最大堆大小的不适当值。
【解决方案2】:

分配取决于使用的操作系统。 如果您分配了太多内存,也许您最终可能会将部分加载到交换中,这很慢。 如果你的程序运行得更慢,取决于 VM 如何处理内存。

我不会指定一个不太大的堆以确保它不会占用所有内存以防止 VM 变慢。

【讨论】:

    【解决方案3】:

    GC 的质量(除非有错误的 GC)不会影响内存泄漏,因为内存泄漏是应用程序的产物 - GC 无法收集非实际垃圾。

    如果 JVM 需要更多内存,它会从系统中获取。如果系统可以交换,它将交换(就像任何其他进程一样)。如果系统无法交换,您的 JVM 将失败并出现系统错误,而不是 OOM 异常,因为系统无法满足请求,这实际上是致命的。

    作为一项规则,您永远不希望将活动的 JVM 部分换出。当系统在虚拟内存系统中循环页面时,GC 事件会让你崩溃。将空闲的后台 JVM 作为一个整体换出是一回事,但如果你的机器是 1G 的 RAM,而你的主进程需要 1.5GB,那么你就有一个大问题了。

    JVM 喜欢呼吸的空间。我见过 JVM 在没有足够内存时陷入 GC 死亡螺旋,即使它们没有内存泄漏。他们根本没有足够的工作集。添加另一块堆将 JVM 从糟糕的锯齿状 GC 图转变为快乐的锯齿状 GC 图。

    给 JVM 所需的内存,你和它都会更快乐。

    【讨论】:

      【解决方案4】:

      “内存”和“RAM”不是一回事。内存包括虚拟内存(交换),因此您可以在出现 OutOfMemoryError 之前分配总共可用的 RAM + 可用交换。

      【讨论】: