10

我们的 glassfish 实例每两周关闭一次,有一段时间使用java.lang.OutOfMemoryError: PermGen space. 我将 PermGen 空间增加到 512MB,并开始使用jstat -gc. 两周后,我想出了下图,它显示了 PermGen 空间是如何稳定增长的(x 轴上的单位是分钟,y 轴是 KB)。 PermGen 使用量增加图

我尝试在谷歌上搜索某种可以查明错误的分析工具,并且在此处提到的 jmap 上的一个线程,这被证明是非常有帮助的。在从 转储的大约 14000 行中jmap -permstats $PID,包含大约 12500行groovy/lang/GroovyClassLoader$InnerLoader,指向我们自己的 Groovy 代码或 Groovy 本身的某种内存泄漏。我必须指出,Groovy 占相关代码库的比例不到 1%。

下面的示例输出:

class_loader    classes bytes   parent_loader   alive?  type

<bootstrap> 3811    14830264      null      live    <internal>
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,尽管我不确定在这种情况下这意味着什么。我不知道如何从这里开始。

附录

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

4

2 回答 2

3

我们遇到了类似的问题(崩溃间隔 1 周)。问题似乎在于 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();
于 2012-05-07T14:40:59.030 回答
-6

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

于 2011-05-18T14:16:34.180 回答