首页 文章

Groovy更新导致PermGen中大量死亡的GroovyClassLoaders

提问于
浏览
2

我有一个Java 7项目,每n分钟由n个进程运行脚本 . 以下是运行脚本的代码示例 .

ScheduledFuture scheduledFuture = scheduledService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try (GroovyClassLoader cl = new GroovyClassLoader()) {
                    // Load up reusable script modules in the class loader
                    Class scriptClass = cl.parseClass(scriptSource);
                    Foo script = optimizationClass.newInstance();

                    // Tell Groovy that we don't need class meta info
                    GroovySystem.getMetaClassRegistry().removeMetaClass(scriptClass);
                    script.run();
                    cl.clearCache();
                } catch (IOException e) {
                    LOGGER.error("Failed to cleanup Groovy class loader, this will cause a memory leak", e);
                }
            }
        }, 0, scheduledRun, TimeUnit.SECONDS);

        scheduledFuture.get();

由于某种原因,使用Groovy 2.1.7,Perm Gen中没有内存泄漏 . 当升级到Groovy 2.3.8或Groovy 2.2.0时,Perm Gen不断充满死亡的Groovy类加载器 .

0x000000071ada2cd0 33 488160 0x000000071b2493c8死常规/郎/ GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x00000007265883b8 33 488160 0x0000000725837270死常规/郎/ GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x00000007157b5da0 26 370736 0x000000072326f468活组织/ Codehaus的/常规/运行/调用点/ CallSiteClassLoader @ 0x00000007c831d388 0x000000071ada1fb0 32 423944 0x000000071af03a98死常规/郎/ GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x0000000719d605b0 32 456520 0x000000071af04798死常规/郎/ GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x0000000725b82500 0 0 0x000000072326f468死常规/郎/ GroovyClassLoader @ 0x00000007c74c33e8 0x00000007263eef80 34 532448 0x0000000726d5c678死常规/郎/ GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x000000072687b3c8 33 485288 0x0000000726c36340 dead groovy / lang / GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x0000000725d56db0 33 485288 0x000000072607bcc0 dead groovy / lang / GroovyClassLoader $ InnerL oader @ 0x00000007c7b70ef8

我等到Full GC发生,但似乎Groovy 2.2之后的任何版本都导致Perm Gen填满 . 我检查了版本之间的版本说明,直到更新版本,我没有注意到任何会触发此更改的更改 .

我在这里检查了类似的问题并尝试了一些建议,但没有运气 . 关于原因的任何想法?

更新:
我在GroovyClassLoader上从2.1.7到2.2.0做了一个关于GrepCode的Diff,并且没有任何变化 . 我还在应用程序运行时获取了一个堆转储文件,并且没有任何GC根源路径用于强引用 .

问题似乎在这里:

Class scriptClass = cl.parseClass(scriptSource);
Foo script = scriptClass.newInstance();

当我不编译脚本时,我在Perm Gen中获得了0个Groovy ClassLoaders . 当我编译脚本但不运行它时,我得到了死的Groovy ClassLoaders .

更新:
找到导致泄漏的代码 .

Foo script = scriptClass.newInstance();

不知道如何解决这个问题,因为我需要创建一个新实例才能运行脚本 .

2 回答

  • 0

    当使用groovy脚本进行编译和运行时,我遇到了同样的问题 . 我终于以这种方式解决了:1 . 如果你使用7以下的java版本,你可以使用下面的代码在编译后清理你的类

    public static void clearAllClassInfo(Class<?> type) throws Exception {
        Field globalClassValue = ClassInfo.class.getDeclaredField("globalClassValue");
        globalClassValue.setAccessible(true);
        GroovyClassValue classValueBean = (GroovyClassValue) globalClassValue.get(null);
        classValueBean.remove(type);
    }
    

    2.否则你很幸运,因为你只需要在SystemProperties中添加一个属性

    -Dgroovy.use.classvalue=true
    
  • 4

    我们遇到类似的问题,文件解析器用groovy编写,内存泄漏就像一个seave - 当你做很多String操作时 . 我们还尝试了类加载器上的clearCache()和.removeMetaClass(),没有用 .

    我们最终通过将groovy模块编译为jar文件并将其包含在项目中来解决这个问题 .

相关问题