PermGen是否可能泄漏到本地堆中?

3
我们正在使用以下设置运行Glassfish应用程序:
-XX:PermSize=1g
-XX:MaxPermSize=2g
-Xms4g
-Xmx4g
-XX:MaxDirectMemorySize=1048576

JDK版本为6u45

我们发现了一个内存泄漏问题 - Glassfish的Java进程不断增长 - RES达到了15GB(我们的服务器有16GB物理内存,因此管理员在达到物理限制之前重启Glassfish),但我们从未遇到过java.lang.OutOfMemoryError

让应用程序运行很长时间后,jmap -permstat的输出显示类加载器占用了~9.5GB (!!!)

class_loader    classes bytes   parent_loader   alive?  type

<bootstrap> 4242    24064120      null      live    <internal>
0x0000000794a4c030  20  274072  0x0000000794a4c098  dead    groovy/lang/GroovyClassLoader$InnerLoader@0x0000000609cdc9f0
...
<many, many Groovy class loaders>
0x000000077f9c80d8  0   0   0x00000007017859f8  dead    groovy/lang/GroovyClassLoader@0x0000000609997f00
0x000000076d63b3e0  0   0   0x00000007017859f8  dead    groovy/lang/GroovyClassLoader@0x0000000609997f00
0x000000075a4c5248  20  261784  0x000000075a4c52b0  dead    groovy/lang/GroovyClassLoader$InnerLoader@0x0000000609cdc9f0
0x000000078ea2e998  0   0   0x00000007017859f8  dead    groovy/lang/GroovyClassLoader@0x0000000609997f00
...
total = 73518   745295  9690318280      N/A     alive=1, dead=73517     N/A    

同时,jmap -heap 显示 PermGen 使用了 700MB:
PS Perm Generation
   capacity = 2147483648 (2048.0MB)
   used     = 823831536 (785.6669769287109MB)
   free     = 1323652112 (1262.333023071289MB)
   38.362645357847214% used

我一直以为通过使用-XX:MaxPermSize-Xmx可以控制Java进程分配多少内存(如果需要更多则会抛出OOM)。 据我理解,该过程应该大致需要:

4G (heap) + 2G (PermGen) + N*1MB (N thread's stacks) ~= 7.5G (by 500 threads)

问题

我们知道泄漏来自旧的Groovy版本和缺少PermGen清除标志,但是为什么类加载器占用了9.5GB的内存,这些内存既不属于PermGen也不属于Java堆?


编辑

只是澄清一下 - 问题不在于如何解决内存泄漏问题,而是关于JVM为什么允许这样的内存分配

1个回答

1
这并不是一个很好的答案,但是需要注意的是,JVM会为垃圾收集(特别是G1)、Java8中的Metaspace:Permgen(因此在您的情况下不适用)、JIT优化和可能驻留在正常垃圾回收堆之外的直接缓冲区使用额外的余地。在任何情况下,分析堆转储以查看应用程序行为。通常错误在于应用程序而不是JVM。此外,您应该让应用程序运行到OutOfMemory,并查看所提到的确切原因。

关于直接缓冲区(我们的代码中没有使用它们),我使用了“-XX:MaxDirectMemorySize=1048576”来确保第三方库不会占用大块本地内存。 - botchniaque

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