64 位 JVM 限制为 300GB 内存?
Posted
技术标签:
【中文标题】64 位 JVM 限制为 300GB 内存?【英文标题】:64-bit JVM limited to 300GB of memory? 【发布时间】:2014-05-07 19:42:48 【问题描述】:我正在尝试在可以为我提供高达 1TB RAM 空间的集群计算环境(运行 CentOS 6.2 Final 版的 IBM LSF)上运行 Java 应用程序。
我可以创建一个最大内存高达 300GB (Xmx) 的 JVM,尽管我需要的不止这些(如果需要,我可以提供详细信息)。
但是,使用 Xmx 选项创建最大内存超过 300GB 的 JVM 似乎是不可能的。更具体地说,我收到了经典的错误消息:
VM 初始化时出错。
无法为对象堆保留足够的空间。
我的(64 位)JVM 的详细信息如下:
OpenJDK 运行时环境 (IcedTea6 1.10.6) (rhel-1.43.1.10.6.el6_2-x86_64)
OpenJDK 64 位服务器虚拟机(build 20.0-b11,混合模式)
我也尝试过使用 Java 7 64 位 JVM,但我遇到了完全相同的问题。
另外,我尝试创建一个JVM来运行一个HelloWorld.jar,但是如果你要求超过-Xmx300G,仍然无法创建JVM,所以我认为这与具体应用程序无关。
有人知道为什么我不能创建一个最大内存超过 300G 的 JVM 吗?
任何人都可以提出解决方案/解决方法吗?
【问题讨论】:
三票接近?和许多赞成票!问题可能与代码无关,但答案将来自开发人员。 你有没有观察过它在什么时候失败了? 貌似参数和它无关; Java 并没有抱怨您指定的值太大,而是报告它 - 不能 - 保留与您指定的一样多。因为它在物理上无法做到这一点。您必须调查为什么不这样做;我将从操作系统的角度开始。 您可能有 1To 的 RAM,但不是在一个连续的段中。因此,操作系统无法将其提供给 JVM 吗? @joh 你什么意思?物理内存不必是连续的段。 en.wikipedia.org/wiki/Virtual_memory 【参考方案1】:我能想到几种可能的解释:
您系统上的其他应用程序正在使用太多内存,目前没有 300Gb 可用。
每个进程的内存大小可能存在资源限制。您可以使用ulimit
进行检查。 (请注意,根据this bug,如果每个进程的资源限制停止JVM分配堆区域,您将收到错误消息。)
这也可能是“过度提交”问题;例如如果您的应用程序在虚拟环境中运行,并且由于来自其他虚拟环境的竞争过多,整个系统无法满足需求。
建议的其他一些想法(IMO)不太可能:
切换 JRE 不太可能产生任何影响。我从未听说过或见过特定 64 位 JVM 中的任意内存限制。
这不太可能是由于没有足够的连续内存。当然不需要连续的物理内存。唯一的可能性可能是交换设备上的连续空间,但我不记得这是典型 Linux 操作系统的问题。
任何人都可以提出解决方案/解决方法吗?
检查ulimit
。
编写一个小型 C 程序,尝试malloc
大量内存,看看在失败之前可以分配多少。
向系统(或管理程序)管理员寻求帮助。
【讨论】:
另一个关于非连续内存的想法:JVM 可能会将一些库或其他内部内容映射到 300GB 的内存区域。之后,它尝试分配堆内存,但找不到连续的地址区域。那将是一个 JVM 错误。并尝试另一个 JVM Luke Jrockit nicht 帮助。 我想这是可能的,但有任何证据表明确实存在这样的错误吗?就像指向 Java 错误数据库中条目的链接? 我不会声称存在实际错误。但是 QO 可以通过 pmap 和不同的内存设置检查是否有一些内存区域在增加设置时地址不会移动。 @StephenC: ulimit(和 ulimit -a)将内存显示为“无限” @critichu - 尝试其他的东西。我只是将这些建议作为可能的原因......在没有任何关于正在发生的事情的真实证据的情况下。【参考方案2】:(已编辑,参见关于交换空间的添加部分)
SHMMAX 和 SHMALL
由于您使用的是 CentOS,您可能遇到了与here for configuring the Oracle DB 所述的SHMMAX
和SHMALL
内核设置类似的问题。在同一链接下是获取和设置正确 SHMALL
设置的示例计算。
连续内存
某些用户已经报告说没有足够的连续内存可用,其他人则说这无关紧要。
我不确定 CentOS 上的 JVM 是否需要连续的内存块。 According to SAS,碎片化内存可以阻止您的 JVM 以较大的最大值启动 Xmx
或启动 Xms
内存设置,但互联网上的其他说法说这没关系。我试图在我的 48GB Windows 工作站上证明或取消证明该声明,但设法以 40GB 的初始和最大设置启动 JVM。我很确定没有该大小的连续块可用,但不同操作系统上的 JVM 可能表现不同,因为每个操作系统的内存管理可能不同(即 Windows 通常隐藏各个进程的物理地址)。
寻找最大的连续内存块
使用/proc/meminfo
查找可用的最大连续内存块,请参见VmAllocChunk
下的值。 Here's a guide and explanation 的所有值。如果您看到的值小于 300GB,请尝试使用恰好低于 VmAllocChunk
的值。
但是,通常这个数字高于物理可用内存(因为它是可用的虚拟内存值),它可能会给你一个误报。这是您可以保留的价值,但是一旦您开始使用它,它可能需要交换。因此,您还应该检查 MemFree
和 Inactive
值。相反,您也可以查看整个列表,看看哪些值不超过 300GB。
您可以检查 64 位 JVM 的其他调整选项
我不确定为什么您似乎遇到了 300GB 的内存限制问题。有那么一刻,我想你可能已经打到了最多的页面。默认为 4kB,300GB 提供78,643,200
页。看起来不像是某个众所周知的神奇数字。例如,如果 2^24
是最大值,那么 16,777,216
页面或 64GB 应该是理论上可分配的最大值。
但是,假设您需要更大的页面(事实证明,这对于大内存 Java 应用程序的性能更好),您应该 consult this manpage on JBoss,它解释了如何使用 -XX:+UseLargePages
和设置kernel.shmmax
(又是)、vm.nr_hugepages
和vm.huge_tlb_shm_group
(不确定是否需要后者)。
给你的系统压力
其他人也已经提出了这个建议。要找出问题出在 JVM 而不是操作系统上,您应该对其进行压力测试。您可以使用的一种工具是Stresslinux。 In this tutorial,您可以找到一些可以使用的选项。您特别感兴趣的是以下命令:
stress --vm 2 --vm-bytes 300G --timeout 30s --verbose
如果该命令失败或锁定您的系统,您就知道操作系统正在限制该内存量的使用。如果成功,我们应该尝试调整 JVM,使其可以使用可用内存。
编辑 Apr6:检查交换空间
内部内存非常大的系统使用很少或不使用交换空间的情况并不少见。对于许多应用程序来说,这可能不是问题,但是 JVM 要求交换可用的交换空间大于请求的内存大小。根据this bug report 的说法,JVM 会尝试自己增加交换空间,但是,正如this SO thread suggested 中的一些答案,JVM 可能并不总是能够这样做。
因此:使用cat /proc/swaps # free
检查当前可用的交换空间,如果小于 300GB,请按照the instructions on this CentOS manpage 为您的系统增加交换空间。
注意 1:我们可以从bugreport #4719001 中推断出,可用交换空间的连续块不是必需的。但是,如果您不确定,remove all swap space and recreate it,应该会删除任何碎片。
注意 2:我看到过一些帖子,例如 this one 报告 0MB
交换空间和能够运行 JVM。这可能是由于 JVM 本身增加了交换空间。尝试手动增加交换空间以确定它是否解决了您的问题仍然没有什么坏处。
过早的结论
我意识到以上都不是对您问题的开箱即用的答案。我希望它能给你一些指导,尽管你可以尝试让你的 JVM 工作。如果问题是您当前使用的 JVM 的限制,您也可以尝试其他 JVM,但从我目前所读的内容来看,不应该对 64 位 JVM 施加限制。
您在 JVM 初始化时得到了正确的错误,这让我相信问题不在于 JVM,而在于操作系统无法遵守 300GB 内存的预留。
我自己的测试表明 JVM 可以访问所有虚拟内存,而不关心可用的物理内存量。如果虚拟内存低于物理内存会很奇怪,但VmAllocChunk
设置应该会在这个方向上给你一个提示(它通常要大得多)。
【讨论】:
【参考方案3】:如果您查看 Java HotSpot VM 的 FAQ section,它提到在 64 位 VM 上,只有 64 个地址位可以使用,因此最大 Java 堆大小取决于物理量系统上存在内存和交换空间。
如果从理论上计算,那么你可以拥有18446744073709551616 MB的内存,但有以上限制。
您必须使用 -Xmx
命令来定义 JVM 的最大堆大小,By default,Java 在 64 位 JVM 上使用 64 + 30% = 83.2MB。
我在我的机器上尝试了下面的命令,它看起来工作正常。
java -Xmx500g com.test.TestClass
我也尝试以 TB 为单位定义最大堆,但它不起作用。
【讨论】:
【参考方案4】:以 JVM 进程的用户身份运行 ulimit -a 并确认您的内核没有限制您的最大内存大小。您可能需要编辑 /etc/security/limit.conf
【讨论】:
【参考方案5】:根据this discussion,LSF 不会将节点内存池化到单个共享空间中。您正在为此使用其他东西。阅读该文件的文档,因为它可能无法执行您要求它执行的操作。特别是,它可能无法分配跨越所有节点的单个连续内存区域。通常这不是必需的,因为应用程序会多次调用 malloc。但是 JVM 为自己简化事情,希望通过有效地调用 malloc 一次来为整个堆分配(或保留)一个连续的区域。或者它可能是与您用来模拟巨型共享内存机器的任何东西相关的其他东西。
【讨论】:
我一般同意,但我们的环境每个节点有 1TB 内存(不是总共 1TB),我要求 LSF 在同一个节点上执行所有操作 @critichu 在这种情况下,你有一个令人印象深刻的环境。以上是关于64 位 JVM 限制为 300GB 内存?的主要内容,如果未能解决你的问题,请参考以下文章
32位JVM和64位JVM的最大堆内存分别是多数?32位和64位的JVM,int类型变量的长度是多数?