小编djh*_*djh的帖子

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

问题背景

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

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
Run Code Online (Sandbox Code Playgroud)

旗帜,工作正常.当类加载器是GC时,动态类正在卸载.

问题描述

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

jvisualvm截图

现在,Launcher$AppClassLoader有一个parallelLockMap定义的属性java.lang.ClassLoader.显然,这ConcurrentHashMap用于在Java 7中保存并行类加载锁.查看源代码.

此映射中保留的条目具有String键(锁定适用的类名称)和Object值(锁定对象).有两种泄漏密钥:

"groovy.runtime.metaclass.MyDynamicallyLoadedClassNameMetaClass"
"MyDynamicallyLoadedClassNameBeanInfo"
Run Code Online (Sandbox Code Playgroud)

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

测试用例

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

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

确保使用上面的JVM标志运行它,以便用尽堆空间,而不是PermGen空间.再次,PermGen很好地收集垃圾,没有泄漏.

看看这导致了什么?

问题

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

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

编辑:我在这里提交了一个Groovy JIRA …

java groovy memory-leaks classloader java-7

5
推荐指数
0
解决办法
1443
查看次数

Grails单元测试:通过grailsApplication访问定义的bean

我有一些(非Grails-artifact)类通过传递grailsApplication对象来访问服务层bean .但是,我无法对以这种方式实现的类进行单元测试.为什么bean不在主上下文中注册?

@TestMixin(GrailsUnitTestMixin)
class ExampleTests {
  void setUp() {}

  void tearDown() {}

  void testSomething() {
    defineBeans {
      myService(MyService)
    }

    assert grailsApplication.mainContext.getBean("myService") != null
  }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码失败了:

org.springframework.beans.factory.NoSuchBeanDefinitionException:没有定义名为'myService'的bean

我想要做的是通过grailsApplication从普通的旧Java类访问服务.这有效,但不适用于单元测试环境.我应该采用不同的方式吗?

class POJO {
  MyService myService;

  public POJO(GrailsApplication grailsApplication) {
    myService = (MyService) grailsApplication.getMainContext().getBean("myService");
  }
}
Run Code Online (Sandbox Code Playgroud)

grails grails-2.0

2
推荐指数
2
解决办法
1万
查看次数

标签 统计

classloader ×1

grails ×1

grails-2.0 ×1

groovy ×1

java ×1

java-7 ×1

memory-leaks ×1