无法为对象堆预留足够的空间
背景
我们拥有大约20个linux刀片库。 有些正在运行Suse,有些正在运行Redhat。 全部共享包含以下3个文件夹的NAS空间:
我们所有的机器都有2个处理器(超线程),4GB物理内存和4GB交换空间。 我们将每台机器在给定时间可以处理的'工作'数量限制为6(这个数字可能需要改变,但是这并不会导致当前的问题,所以请暂时忽略它)。
我们的一些工作设置了512MB的Max Heap大小,其他一些则保留了2048mb的Max Heap大小。 同样,我们意识到如果6个作业在堆大小设置为2048的同一台机器上启动,我们可以检查可用内存,但据我们所知,这还没有发生。
问题
一旦某个作业立即失败,并显示以下消息:
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
我们过去常常将同一台机器上同时运行的太多作业记录下来。 问题很少发生(MAYBE每月一次),我们只需重新启动它,一切都会好起来的。
这个问题最近变得更糟了。 我们所有要求最大堆大小为2048米的作业几乎每次都会立即失败,并且在完成之前需要重新启动几次。
我们已经去了单独的机器,并尝试用相同的结果手动执行它们。
调试
事实证明,这个问题只存在于我们的SuSE盒子中。 之所以会更频繁地发生,是因为我们增加了更多的机器,而新的机器是SuSE。
SuSE盒子上的'cat / proc / version'给我们:
Linux version 2.6.5-7.244-bigsmp (geeko@buildhost) (gcc version 3.3.3 (SuSE Linux)) #1 SMP Mon Dec 12 18:32:25 UTC 2005
RedHat盒子上的'cat / proc / version'给我们:
Linux version 2.4.21-32.0.1.ELsmp (bhcompile@bugs.build.redhat.com) (gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-52)) #1 SMP Tue May 17 17:52:23 EDT 2005
'uname -a'为我们提供了以下两种类型的机器:
UTC 2005 i686 i686 i386 GNU/Linux
机器上没有任何作业正在运行,并且没有其他进程正在使用大量内存。 目前运行的所有进程可能总共使用100mb。
'top'目前显示如下:
Mem: 4146528k total, 3536360k used, 610168k free, 132136k buffers
Swap: 4194288k total, 0k used, 4194288k free, 3283908k cached
'vmstat'目前显示如下:
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
0 0 0 610292 132136 3283908 0 0 0 2 26 15 0 0 100 0
如果我们使用以下命令行(1850mb的Max Heap)启动一项工作,它会正常启动:
java/bin/java -Xmx1850M -cp helloworld.jar HelloWorld
Hello World
如果我们将最大堆大小提升到1875mb,它会失败:
java/bin/java -Xmx1875M -cp helloworld.jar HelloWorld
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
很明显,当前正在使用的内存用于缓冲/缓存,这就是为什么这么少显示为“免费”的原因。 不清楚的是为什么有一个神奇的1850mb行,其中更高的意味着Java无法启动。
任何解释将不胜感激。
您使用的是32位操作系统,因此您将看到总大小的限制。 其他答案已经更详细地介绍了这一点,所以我会避免重复他们的信息。
最近我们在服务器上注意到的一个行为是,如果用-Xmx
指定最大堆大小而不指定具有-Xms
的最小堆大小,将导致Java的服务器VM立即尝试分配最大堆大小所需的全部内存。 当然,如果应用程序达到堆大小,那就是您需要的内存量。 但有可能的是,你的应用程序将以相对较小的堆开始,并可能在稍后的某个时间需要更大的堆。 此外,指定最小堆大小将允许您以较小的堆开始您的应用程序并逐渐增加堆。
所有这些都不会帮助你增加最大堆大小,但我认为它可能有帮助,所以...
正如其他响应中所提出的,问题是虚拟地址空间耗尽的原因。 32位linux用户空间程序通常限制为3GB的AS; 内核使用剩余的1GB(理由:由于最高1GB是内核固定映射,因此在服务系统调用时不需要触摸页面表)。
然而,RHEL内核实现了所谓的4GB / 4GB拆分,其中全部4GB AS可用于用户空间进程,代价是运行时间很短(内核位于独立的4GB虚拟AS中)
运行32位操作系统是一个错误; 你应该尽早升级。
我不知道Java是否需要将它堆放在一个连续的块中,但是如果是这样,在32位盒子上要求1.8G的堆听起来就像是一个很高的命令。 假设在JVM启动时有大量的地址空间,几乎一半是免费的。
根据当时加载的其他库,可能不会。 库可以在他们喜欢的任何地方分配内存,所以它可以充分地分割你的地址空间,使得1.8G在一个块中不可用。
无论如何,在Linux 32位上只有大约3G地址空间可用。 库和JVM本身使用一些开始。
链接地址: http://www.djcxy.com/p/14551.html