I have a Java 7 project that runs scripts every n minutes by n processes. Here is an example of the code that runs the scripts.
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();
For some reason with Groovy 2.1.7 there is no memory leak in Perm Gen. When upgrading to Groovy 2.3.8 or Groovy 2.2.0, Perm Gen keeps getting filled with dead Groovy class loaders.
0x000000071ada2cd0 33 488160 0x000000071b2493c8 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00000007c7b70ef8 0x00000007265883b8 33 488160 0x0000000725837270 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00000007c7b70ef8 0x00000007157b5da0 26 370736 0x000000072326f468 live org/codehaus/groovy/runtime/callsite/CallSiteClassLoader@0x00000007c831d388 0x000000071ada1fb0 32 423944 0x000000071af03a98 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00000007c7b70ef8 0x0000000719d605b0 32 456520 0x000000071af04798 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00000007c7b70ef8 0x0000000725b82500 0 0 0x000000072326f468 dead groovy/lang/GroovyClassLoader@0x00000007c74c33e8 0x00000007263eef80 34 532448 0x0000000726d5c678 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00000007c7b70ef8 0x000000072687b3c8 33 485288 0x0000000726c36340 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00000007c7b70ef8 0x0000000725d56db0 33 485288 0x000000072607bcc0 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00000007c7b70ef8
I wait until a Full GC happens but it seems that any version after Groovy 2.2 has been causing Perm Gen to fill up. I checked the release notes between the version I was at up to the updated version and I didn't notice any changes that would trigger this.
I checked on here for similar issues and tried a few suggestions but no luck. Any ideas as to the cause?
Update:
I did a Diff on GrepCode on GroovyClassLoader from 2.1.7 to 2.2.0 and there was no changes. I also took a heap dump file when the application was running and there wasn't any paths to GC roots for strong references.
The issue seems to be around here:
Class scriptClass = cl.parseClass(scriptSource);
Foo script = scriptClass.newInstance();
When I don't compile the script I got 0 Groovy ClassLoaders in Perm Gen. When I compile the script but don't run it, I get dead Groovy ClassLoaders.
Update:
Found the code that is causing the leak.
Foo script = scriptClass.newInstance();
Not sure how to fix this as I need to create a new instance in order to run the script.
i had same problem when using groovy script for compiling and running. I finally work out with these way: 1. if you work with java version under 7 , you can use codes below to clean your class after compiled
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. otherwise you are lucky, because you just need add an properties in SystemProperties
-Dgroovy.use.classvalue=true
We've had similar issues with a file parser written in groovy, memory leaks like a seave - when you do a lot of String manipulation. We also tried the clearCache() on the classloader and also .removeMetaClass() with no use.
We finally got around this problem by compiling the groovy module as a jar file and including it in the project.
来源:https://stackoverflow.com/questions/27451058/groovy-update-causing-a-ton-of-dead-groovyclassloaders-in-permgen