我有两台Linux机器(都是虚拟机),一台有12GB内存,另一台有8GB内存。
我尝试在两台机器上启动相同的java程序,最大可能的最大堆大小(使用-Xmx标志)。以下是我得到的结果。
如果我指定超出上限的最大堆大小,我会得到以下错误。
Error occurred during initialization of VM
Could not allocate metaspace: 1073741824 bytes
我检查了两个系统中的可用内存(使用free
命令),我得到了跟进。
我的问题是,是什么决定了java程序可以启动的最大最大堆大小,这不会导致上述错误? (当程序给出上述错误时,系统有足够的内存来分配1073741824
个字节的内存)
答案 0 :(得分:7)
我从JDK bug找到了有趣的评论(JDK 9版本中的错误,而不是8中的错误。它说错误是在8.x版本中修复的,但不会告诉小版本号。
如果虚拟内存受限于" ulimit -v",并且服务器有大量RAM,那么如果没有额外的命令行参数,JVM就无法启动。
// After "ulimit -v" The jvm does not start with default command line.
$ ulimit -S -v 4194304
$ java -version
Error occurred during initialization of VM
Could not allocate metaspace: 1073741824 bytes
<强>注释:强>
问题似乎是我们必须指定MALLOC_ARENA_MAX。
如果我设置环境变量MALLOC_ARENA_MAX = 4,则jvm可以在没有任何额外参数的情况下启动。
我想这不是可以从jvm修复的东西。如果是这样,我们可以关闭这个错误。
使用&#34; UseConcMarkSweepGC&#34;那么上面的命令行不起作用。 我试图添加MaxMetaspaceSize = 128m,但它没有帮助。 我确信有一个论点可以让它发挥作用,但我还没找到。 使用有限的虚拟内存配置GC不是非常用户友好。
根据您的要求更改参数并尝试使用此参数。
ulimit -S -v 4194304
java -XX:MaxHeapSize=512m -XX:InitialHeapSize=512m -XX:CompressedClassSpaceSize=64m -XX:MaxMetaspaceSize=128m -XX:+UseConcMarkSweepGC -version
答案 1 :(得分:1)
我使用ravindra提供的线索进行了一些实验,发现最大最大堆大小与系统中可用的总虚拟内存有直接关系。
系统中的虚拟内存总量(以KB为单位)可以找到:
ulimit-v
虚拟内存总量可以通过以下方式更改:
ulimit -v <new amount in KB>
可能的最大最大堆大小比虚拟内存少大约2GB。如果使用ulimit -v unlimited
指定无限制的虚拟内存,则可以为最大堆大小指定任何大的值。
答案 2 :(得分:0)
您可用的内存是空闲RAM和交换空间的组合。它还取决于系统是否启用了overcommit - 如果是这样,内核将允许程序分配比实际可用内存更多的内存(在合理的限制范围内),因为程序通常分配的内容超过它们真正要使用的内存
请注意,默认情况下会启用overcommit。要将其停用,请将2
写入/proc/sys/vm/overcommit_memory
。 (奇怪的是,0
的值并不意味着“没有过度使用”。)但是首先阅读过度使用的文档是个好主意。