我们已经让我们的glassfish实例每两周停一次java.lang.OutOfMemoryError: PermGen space
。我将PermGen空间增加到512MB,并使用jstat -gc
转储内存使用量。两周后,我想出了下图,显示了PermGen空间是如何稳定增加的(x轴上的单位是分钟,y轴是KB)。
我尝试使用谷歌搜索可以查明错误的某种分析工具,并在SO上提到的一个线程提到了jmap,这被证明是非常有帮助的。在从jmap -permstats $PID
转储的大约14000行中,大约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
....
那么我该如何继续了解更多关于导致此问题的代码?
从this article我推断我们的Groovy代码是在某处动态创建类的。从jmap的转储中我可以看到大多数死对象/类(?)具有相同的parent_loader,尽管我不确定这在这种情况下意味着什么。我不知道怎么从这里开始。
对于后来者,值得指出接受的答案无法解决问题。它只是通过不存储如此多的类信息来延长重启前所需的时间十倍。实际修复我们问题的是摆脱生成它的代码。我们使用验证(按合同设计)框架OVal,其中可以使用Groovy编写自定义约束作为方法和类的注释。在普通Java中删除注释以支持显式的前置条件和后置条件是很无聊的,但它完成了工作。我怀疑每次检查OVal约束时都会创建一个新的匿名类,并且关联的类数据以某种方式导致内存泄漏。
答案 0 :(得分:3)
我们遇到了类似的问题(崩溃之间一周)。麻烦似乎是Groovy缓存元方法。我们最终使用的代码基于this discussion和bug report
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();
答案 1 :(得分:-5)
如果您正在使用Sun JVM将其更改为IBM JVM,我希望它能正常工作:)