我们在一个有大量内存(32G)的盒子上运行64位RHEL5的32位JVM。出于不同的原因,此过程需要相当大的托管堆和permgen空间 - 目前,它使用以下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千字节(3.06G)的内存,但当它试图超过3G时,内存分配失败。
任何想法 a)为什么会发生这种情况 b)如何避免这种情况
感谢。 伴侣
答案 0 :(得分:3)
典型虚拟机中有很多开销未计入虚拟机核算,因为它基本上被过程的本机元素窃取 - 例如用于执行系统库的本机级代码的.so文件中的映射不计入基本VM记帐中。您的典型共享库映射到内存的最高GB,因此如果您尝试将内存分配到此区域,您将被拒绝,因为它将超出共享库的内存区域 - 大多数操作系统上的内存分配由当你要求更多记忆时,提出的简单栏。当你要求内存和条形码与其他用途冲突时,它就会失败。接下来的大部分细节都与此有关。
你需要避免在32位进程中需要这么多内存。这是一项根本性挑战。获得一个64位的虚拟机可以让你使用比其它方式更多的内存 - 它只是在这种情况下可以使用。
如果您使用的是32位进程,则很可能遇到32位进程的有效地址空间限制。对于Windows,这最大约为3GB - 高于此值的任何内容都保留给I / O空间和内核。您可以移动它,但它倾向于破坏为32位操作系统设计的应用程序/驱动程序。
对于Linux,每个进程最终会有大约3GB的可用可寻址RAM,剩下的就被内核使用并映射到共享库中。该限制被称为“地址空间限制”,我认为它可以调整。
如何避免它?好吧,在大多数情况下,你不能,这是32位地址空间的物理限制,以及在与32位操作系统的进程相同的地址空间中使用内核/ IO的需求。
使用64位操作系统,您可以(大部分)使用所有64位地址空间,这远远超出您的需要。
答案 1 :(得分:0)
启动JVM时,会立即为其分配最大大小。使用了多少内存并不重要。您的应用程序可以处理大约3 GB,其中大约2.3 GB分配给堆和perm gen。其余的可用于共享库(通常大约200 MB)和线程堆栈。
当解决方案相对简单(使用64位JVM)时,担心为什么不能使用完整的3 GB地址并不是很有用我假设您没有任何共享库提供32位。但是,如果您有其他共享库,则可以轻松使用100个MB。