(已编辑,参见关于交换空间的添加部分)
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 设置应该会在这个方向上给你一个提示(它通常要大得多)。