我们正在使用以下设置运行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
显示使用700MB的PermGen:
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如何允许这样的内存分配 。
答案 0 :(得分:1)
不是一个答案,但是。
这很棘手。请注意,JVM将为Garbage collection
(尤其是G1)使用额外的摆动空间,在Java8中使用Metaspace:Permgen(因此在您的情况下不适用),JIT优化以及可能direct buffers驻留在正常的垃圾收集堆之外。
在任何一种情况下,分析堆转储以查看应用程序行为是什么。通常,错误在应用程序中比在JVM中。此外,您应该让应用程序运行到OutOfMemory
并查看提到的确切原因。