64位JVM限于300GB的内存?

我试图在集群计算环境(运行CentOS 6.2版本的IBM LSF)上运行一个Java应用程序,它可以提供高达1TB的RAM空间。

我可以创build一个高达300GB的最大内存(Xmx)的JVM,尽pipe我需要更多(如果需要,我可以提供详细信息)。

但是,使用Xmx选项创build具有超过300GB最大内存的JVM似乎是不可能的。 更具体地说,我得到了经典的错误信息:

VM初始化期间发生错误。

无法为对象堆预留足够的空间。

我的(64位)JVM的细节如下:

OpenJDK运行时环境(IcedTea6 1.10.6)(rhel-1.43.1.10.6.el6_2-x86_64)

OpenJDK 64位服务器虚拟机(内置20.0-b11,混合模式)

我也尝试过使用Java 7 64位JVM,但是我遇到了完全相同的问题。

此外,我试图创build一个JVM来运行HelloWorld.jar,但是如果您要求超过-Xmx300G,仍然会导致JVM创build失败,所以我不认为它与特定的应用程序有任何关系。


有没有人有任何想法,为什么我不能创build超过300G的最大内存的JVM?

任何人都可以请build议一个解决scheme/解决方法?

我可以想到几个可能的解释:

  • 您的系统上的其他应用程序正在使用太多的内存,现在没有可用的 300Gb。

  • 每个进程的内存大小可能会有一个资源限制。 你可以使用ulimit来检查这个。 (请注意,根据此错误 ,如果每进程资源限制停止JVM分配堆区域,您将收到错误消息。)

  • 这也可能是一个“过度提交”的问题; 例如,如果您的应用程序是虚拟运行的,整个系统无法满足需求,因为与其他虚拟机竞争太激烈。


其他一些想法build议是(IMO)不太可能的:

  • 切换JRE不太可能会有所作为。 我从来没有听说过或看到特定的64位JVM中的任意内存限制。

  • 这不可能是因为没有足够的连续内存。 当然,连续的物理内存不是必需的。 唯一的可能性可能是交换设备上的连续空间,但我不记得这是典型的Linux操作系统的问题。


任何人都可以请build议一个解决scheme/解决方法?

  • 检查ulimit

  • 编写一个小C程序,试图malloc大量的内存,看看有多less可以分配之前,它失败。

  • 询问系统(或pipe理程序)pipe理员的帮助。

(已编辑,请参阅交换空间的添加部分)

SHMMAX和SHMALL

由于您正在使用CentOS,因此您可能会遇到类似于SHMMAXSHMALL内核设置的问题,如configurationOracle DB所述 。 在同样的链接下,用于获取和设置正确的SHMALL设置的示例计算。

连续的记忆

某些用户已经报告说没有足够的连续内存可用,其他人则说这是不相关的。

我不确定CentOS上的JVM是否需要连续的内存块。 根据SAS的说法 ,碎片内存可能会阻止您的JVM使用大的最大Xmx启动,或启动Xms内存设置,但是互联网上的其他声明表示无关紧要。 我尝试在我的48GB Windows工作站上certificate或解决这个声明,但是设法以40GB的初始和最大设置启动JVM。 我非常肯定,没有可用的连续块,但是不同操作系统上的JVM可能会有不同的performance,因为每个操作系统的内存pipe理可能不同(即,Windows通常隐藏单个进程的物理地址)。

find最大的连续内存块

使用/proc/meminfo查找可用的最大连续内存块,请参阅VmAllocChunk下的值。 这是所有值的指导和解释 。 如果您看到的值小于300GB,请尝试一个VmAllocChunkVmAllocChunk的值下的值。

但是,通常这个数字比物理可用内存高(因为它是可用的虚拟内存值),它可能会给你一个误报。 这是您可以保留的价值,但一旦开始使用它,可能需要交换。 因此,您应该检查MemFreeInactive值。 相反,你也可以看看整个列表,看看什么值不超过300GB。

其他调优选项,你可以检查64位JVM

我不知道为什么你似乎在300GB的内存限制问题。 有一刻,我想你可能已经达到了最大的页数。 默认为78,643,200 ,300GB为78,643,200页。 看起来不像一些知名的神奇数字。 例如,如果2^24是最大值,那么16,777,216页或64GB应该是您理论上可分配的最大值。

但是,假设为了争辩,您需要更大的页面(事实certificate,对于大型内存Java应用程序来说性能更好),您应该参考JBoss上的这个手册页 ,它解释了如何使用-XX:+UseLargePages并设置kernel.shmmax (那里再次), vm.nr_hugepagesvm.huge_tlb_shm_group (不知道后者是必需的)。

强调你的系统

其他人也已经提出这一点。 要发现问题出在JVM而不是OS上,你应该强调testing。 一个你可以使用的工具是Stresslinux 。 在本教程中 ,您可以find一些可以使用的选项。 您特别感兴趣的是以下命令:

 stress --vm 2 --vm-bytes 300G --timeout 30s --verbose 

如果该命令失败,或者locking了系统,则知道操作系统正在限制使用该内存量。 如果成功,我们应该尝试调整JVM,使其可以使用可用的内存。

编辑Apr6:检查交换空间

内存容量非常大的系统很less使用或不使用交换空间。 对于许多应用程序来说,这可能不成问题,但JVM要求交换可用交换空间大于请求的内存大小。 根据这个错误报告 ,JVM会尝试增加交换空间本身,然而,正如本SO线程中的一些答案所build议的那样 ,JVM可能并不总能这样做。

因此:使用cat /proc/swaps # free检查当前可用的交换空间,如果它小于300GB,请按照CentOS联机帮助页上的说明增加系统的交换空间。

注1:我们可以从bugreport#4719001中扣除一个连续的可用交换空间块不是必需的。 但是,如果你不确定, 删除所有的交换空间,并重新创build它 ,它应该删除任何碎片。

注2:我看过几个这样的post,报告0MB交换空间能够运行JVM。 这可能是由于JVM增加了交换空间本身。 仍然不会尝试增加交换空间手工来找出它是否修复你的问题。

过早的结论

我意识到,以上的不是对你的问题的开箱即用的答案。 我希望它给你一些指示,尽pipe你可以尝试让你的JVM工作。 如果问题结果是您当前正在使用的JVM的限制,那么您也可以尝试使用其他JVM,但从目前为止所读取的内容来看,对于64位JVM,不应该施加任何限制。

你在JVM初始化的时候得到了错误,这让我相信问题不在于JVM,而是由于操作系统无法遵守300GB的内存预留。

我自己的testing表明,JVM可以访问所有的虚拟内存,并不关心可用的物理内存的数量。 如果虚拟内存低于物理内存,那将会很奇怪,但是VmAllocChunk设置应该会给你一个提示(通常要大得多)。

如果你看看Java HotSpot VM的FAQ部分 ,它提到在64位VM上,只有64个地址位可以使用,因此最大的Java堆大小取决于物理内存和交换空间的数量目前在系统上。

如果你理论上计算,那么你可以有一个18446744073709551616 MB的记忆,但是有上面的限制。

您必须使用-Xmx命令为JVM定义最大堆大小。 默认情况下 ,Java在64位JVM上使用64 + 30%= 83.2MB。

我试着在我的机器下面的命令,它看起来工作正常。

 java -Xmx500g com.test.TestClass 

我也试图在TB中定义最大的堆,但它不起作用。

运行ulimit -a作为JVM进程的用户,并validation你的内核不限制你的最大内存大小。 您可能需要编辑/etc/security/limit.conf

根据这个讨论 ,LSF不会将节点内存池合并成一个共享空间。 你正在使用其他的东西。 阅读某些文档,因为它可能无法完成你所要求的工作。 尤其是,它可能无法分配跨越所有节点的单个连续区域的内存。 通常这不是必须的,因为应用程序会对malloc进行多次调用。 但是,JVM为了简化事情本身,希望通过有效地调用malloc一次来为整个堆分配(或保留)一个连续的区域。 或者它可能与你用来模拟一个巨大的共享内存机器的东西有关。