JVM和内存使用 - JRun服务器未使用完整的PSPermGen分配?

4

我试图理解为什么ColdFusion 9(JRun)服务器会抛出以下错误:

java.lang.OutOfMemoryError: requested 32756 bytes for ChunkPool::allocate. Out of swap space?

JVM参数如下:
-server -Dsun.io.useCanonCaches=false -XX:MaxPermSize=192m -XX:+UseParallelGC -

当转储发生时,我正在运行jconsole,并尝试将一些数字与上面的-XX:MaxPermSize=192m设置进行协调。当JRun死亡时,它具有以下内存使用情况:

Heap
 PSYoungGen      total 136960K, used 60012K [0x5f180000, 0x67e30000, 0x68d00000)
  eden space 130624K, 45% used [0x5f180000,0x62c1b178,0x67110000)
  from space 6336K, 0% used [0x67800000,0x67800000,0x67e30000)
  to   space 6720K, 0% used [0x67110000,0x67110000,0x677a0000)
 PSOldGen        total 405696K, used 241824K [0x11500000, 0x2a130000, 0x5f180000)
  object space 405696K, 59% used [0x11500000,0x20128360,0x2a130000)
 PSPermGen       total 77440K, used 77070K [0x05500000, 0x0a0a0000, 0x11500000)
  object space 77440K, 99% used [0x05500000,0x0a043af0,0x0a0a0000)

我的第一个问题是,转储文件显示PSPermGen是问题所在——它说总共是77440K,但根据我的192m JVM参数,应该是196608K,对吗?我错过了什么?这与其他非堆池——代码缓存有关吗?
我在运行32位机器上,Windows Server 2008 Standard。我正在考虑增加PSPermGen JVM参数,但我想了解为什么它似乎没有使用其当前分配。
提前致谢!
3个回答

7
"内存交换空间不足"的 OOME 是指当 JVM 请求操作系统提供更多内存时,操作系统无法满足请求,因为所有交换(磁盘)空间已经被分配完毕。基本上,您已经达到了系统范围内可用虚拟内存量的硬性限制。
这可能是您的应用程序或 JVM 没有任何问题,也可能是将 -Xmx 等增加到超出系统支持能力的结果。
解决此问题有三种方法:
- 向系统添加更多物理内存。 - 增加系统中可用的交换空间;例如,在 Linux 上查看 swapon 等手册条目。(但要小心活跃虚拟内存与物理内存的比率不要过大...否则您的系统可能会“抖动”,性能会急剧下降。) - 减少运行在系统上的进程数量和大小。
如果您因为增加 -Xmx 来解决其他 OOME 而陷入这种情况,那么现在是追踪潜在的内存泄漏问题的好时机。

我已经使用-XX:+HeapDumpOnOutOfMemoryError配置了JVM,并且下次发生内存泄漏时,我将使用Eclipse Memory Management插件来找到问题的根源。同时,我可能会考虑暂时减小堆大小。 - Ciaran Archer
1
我确实是一个内存泄漏!我在这里写下了我的经历,希望能对其他人有所帮助:http://flydillonfly.wordpress.com/2010/08/24/cf-out-of-stack-space/ - Ciaran Archer

2
"ChunkPool::allocate. Out of swap space"通常意味着JVM进程无法为其内部处理分配内存。这通常与您的堆使用情况无直接关系,因为JVM进程本身已经用尽了内存。请检查Windows中JVM进程的大小。您可能已经达到了上限。这个错误报告也给出了一个解释。http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5004956这通常是由于应用程序没有释放非Java对象而不是堆上的Java对象造成的。一些常见的原因包括:
  • 线程堆栈大小过大,或者许多线程被生成但没有正确清理。线程堆栈存在于本地的“C”内存中,而不是Java堆上。我自己也见过这个问题。
  • 通过编程方式创建Swing / AWT窗口,并在不再使用时未进行处理。AWT后面的本机小部件也不在堆上。
  • nio的直接缓冲区没有被释放。直接缓冲区的数据分配到本地进程内存中,而不是Java堆上。
  • jni调用中的内存泄漏。
  • 打开了许多文件但没有关闭。

我在诊断类似问题时发现了这篇博客很有帮助。http://www.codingthearchitecture.com/2008/01/14/jvm_lies_the_outofmemory_myth.html


谢谢,它将读取所有这些内容。对于JVM PSPermGen参数与我的转储显示的PSPermGen内存量要小得多但占用99%,您有任何评论吗?为什么没有完全分配?那是被“C”内存使用了吗? - Ciaran Archer
1
@Ciaran MaxPermSize仅设置PSPermGen的上限,JVM可以分配更少的空间。PermGen几乎满是正常的,JVM很少在那里留下太多余地。如果您运行像visual VM这样的工具来监视应用程序,它将生成PermGen的图形,以便您可以实时查看堆是如何管理的。我怀疑在您的应用程序需要192m的PermGen之前,PermGen的完整限制没有被分配,因此出现了ChunkPool :: allocate错误。 - Aaron
此外,当您的PermGen空间耗尽时,会有一个特殊的错误消息:它是“java.lang.OutOfMemoryError: PermGen space”。 - Aaron
好的,看起来PermGen空间可能并不是我的问题,尽管在我的转储中显示为99%已满?该死。有人知道如何使用Windows perfmon计数器测量“交换”空间吗? - Ciaran Archer

1

请检查您的 setDomainEnv.cmd (.sh) 文件。其中会有三个关于 PermSize 的不同条件 -XX:MaxPermSize=xxxm、-XX:PermSize=xxxm。请在所有地方进行更改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接