使用Java 7并行类加载器的Groovy MetaClass(相关)内存泄漏

时间:2014-04-01 17:00:40

标签: java groovy memory-leaks classloader java-7

问题背景

我运行一个Groovy / Grails系统,动态编译并加载用户定义的代码。这基本上是通过GroovyClassLoader完成的。

我看到动态类本身都加载和卸载就好了。我添加了

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

标志,并且工作正常。当类加载器是GC时,动态类正在被卸载。

问题描述

但是我的堆内存泄漏了,这就是泄漏的来源:

jvisualvm screenshot

现在,Launcher$AppClassLoaderparallelLockMap中定义了一个属性java.lang.ClassLoader。显然,这个ConcurrentHashMap用于在Java 7中保存并行类加载锁。查看source code

此地图中保留的条目包含String个键(锁定适用的类名)和Object值(锁定对象)。有两种泄漏密钥:

"groovy.runtime.metaclass.MyDynamicallyLoadedClassNameMetaClass"
"MyDynamicallyLoadedClassNameBeanInfo"

所以对我来说,当加载parallelLockMap*MetaClass类时,看起来这些键是在*BeanInfo中创建的,但是当关联的动态加载类(及其类)时它们不会被删除元类)卸载。现在,这已经深入到Groovy及其元类系统的内部,并且我已经没有专业知识了。

测试用例

这最终会让你离开堆空间,虽然需要一段时间:

    String newClass = "class CLASSNAME {}"
    while (true) {
        GroovyClassLoader gcl = new GroovyClassLoader()
        Class clazz = gcl.parseClass(newClass.replace("CLASSNAME", "NewClass"+System.nanoTime()))
        clazz.newInstance()
    }

请务必使用上述JVM标志运行此操作,以便用完堆空间,而不是 PermGen 空间。再次,PermGen很好地收集垃圾,没有泄漏。

See where this leads?

问题

1)这是Groovy或Java 7中的错误吗?清除parallelLockMap是谁的责任?我应该提交问题报告吗?

2)有解决方法吗?我正在考虑使用自定义ClassLoader,它不首先尝试将类加载委托给这些MetaClassBeanInfo类的父级,从而阻止调用java.lang.ClassLoader#loadClass(..) 。不过,我不是Java / Groovy类加载方面的专家。

编辑:我已经提交了一个Groovy JIRA here

编辑:在JDK方面,最近报告了此问题here

0 个答案:

没有答案