使用死Groovy代码定位填充PermGen的代码

我们已经使用java.lang.OutOfMemoryError: PermGen space每两周对我们的glassfish实例进行一段时间的研究。 我将PermGen空间增加到512MB,并使用jstat -gc转储内存使用量。 两周后,我想出了下图,显示了PermGen空间是如何稳定增加的(x轴上的单位是分钟,y轴是KB)。 增加PermGen用法的图表

我试着用谷歌搜索某种可以查明错误的分析工具,并在SO上提到了一个提到jmap的post,这被certificate是非常有用的。 在从jmap -permstats $PID转储的大约14000行中,大约12500行包含groovy/lang/GroovyClassLoader$InnerLoader ,指向我们自己的Groovy代码或Groovy本身的某种内存泄漏。 我必须指出,Groovy构造的相关代码库不到1%。

示例输出如下:

 class_loader classes bytes parent_loader alive? type  3811 14830264 null live  0x00007f3aa7e19d20 20 164168 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120 0x00007f3aa7c850d0 20 164168 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120 0x00007f3aa5d15128 21 181072 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120 0x00007f3aad0b40e8 36 189816 0x00007f3a9d31fbf8 dead org/apache/jasper/servlet/JasperLoader@0x00007f3a7d0caf00 .... 

那么我该如何继续了解更多关于导致此问题的代码?

在本文中,我推断我们的Groovy代码是在某处动态创建类。 从jmap的转储我可以看到大多数死对象/类(?)都有相同的parent_loader,虽然我不确定在这种情况下这意味着什么。 我不知道怎么从这里开始。

附录

对于后来者来说,值得指出的是, 接受的答案并不能解决问题 。 它只是通过不存储如此多的课程信息,将十倍重启之前所需的时间延长。 实际修复我们问题的是摆脱生成它的代码。 我们使用validation(按合同设计)框架OVal ,其中可以使用Groovy编写自定义约束作为方法和类的注释。 在普通Java中删除注释以支持显式的前置条件和后置条件是很无聊的,但它完成了工作。 我怀疑每次检查OVal约束时都会创建一个新的匿名类,不知何故关联的类数据导致内存泄漏。

我们遇到了类似的问题(崩溃之间一周)。 麻烦似乎是Groovy缓存元方法。 我们最终使用此代码基于此讨论和错误报告

 GroovyClassLoader loader = new GroovyClassLoader(); Reader reader = new BufferedReader(clob.getCharacterStream()); GroovyCodeSource source = new GroovyCodeSource(reader, name, "xb3.Classifier"); Class groovyClass = loader.parseClass(source); Object possibleClass = groovyClass.newInstance(); if (expectedType.isAssignableFrom(possibleClass.getClass())) { classifiers.put((T) possibleClass, name); } reader.close(); // Tell Groovy we don't need any meta // information about these classes GroovySystem.getMetaClassRegistry().removeMetaClass(possibleClass.getClass()); // Tell the loader to clear out it's cache, // this ensures the classes will be GC'd loader.clearCache(); 

如果您正在使用Sun JVM将其更改为IBM JVM,它将正常工作,我希望:)