【发布时间】:2011-12-18 15:45:57
【问题描述】:
我们有一个在 64 位 RHEL5 下运行的 32 位 JVM,它有足够的内存 (32G)。由于不同的原因,这个过程需要一个相当大的托管堆和永久空间——目前,它使用以下 VM 参数运行:
-Xmx2200M -XX:MaxPermSize=128M -XX:+CMSClassUnloadingEnabled
我最近开始看到 JVM 崩溃,因为它 - 似乎 - 耗尽了本机内存(它无法创建本机线程,或者无法分配本机内存等)。这些崩溃与托管堆的状态没有(直接)相关,因为当这些崩溃发生时,托管堆大约 50-70% 已满。 我知道为托管进程保留的内存接近 2.5 G,这给 JVM 本身留下的内存不超过 0.5G,但是 - 我不明白为什么 0.5 对 JVM 来说还不够,即使有持续的 GCing 正在进行 - 真正的问题是:当我使用 jconsole 连接到进程时,它会说(当前)
Committed virtual memory:
3,211,180 kbytes
这比 3G 还多。我可以想象出于某种原因 JVM 认为它有 3,211,180 kbytes (3.06G) 内存,但当它尝试超过 3G 时,内存分配失败。
任何想法 a) 为什么会这样 b)如何避免这种情况
谢谢。 伴侣
【问题讨论】:
-
在 64 位下,Windows 32 位进程使用完整的 4GB 地址空间 - 操作系统不再需要在 32 位地址空间中保留空间,因为它可以使用 64 位地址空间。
-
好的,刚刚注意到这是 linux 的标签,我仍然认为它以类似的方式工作
-
好吧,如果是,那我还是不明白为什么它会耗尽本机内存。 ://
-
如果“本机内存”是指“物理内存”,那么它可能不是 - 如果您有交换分区,那么操作系统会根据需要将物理内存分页到磁盘上。虚拟地址空间更可能是碎片化的,即即使虚拟地址空间中有空闲空间,空闲空间也被分成许多小块,其中最大的块太小而无法满足所需的分配。
-
是的,很可能是地址空间不足。即使没有碎片,当你有 3.5G 的 JVM 堆时,0.5G 的机器堆也不是很多。对于大量的小对象,GC 本身就可能需要这么多,更不用说线程、类等的非 GC 部分了。
标签: java linux memory-management jvm 32bit-64bit