I download a large number of Groovy scripts (2.4.6) and run them using GroovyScriptEngineImpl in my Java 8, and after a while I have a problem.
There are a few things you need to know:
- I need to recreate a new
GroovyScriptEngineImpl every time I run a script - I have to recreate a new
GroovyClassLoader every time I run the script
I need to do this in order to isolate each script in a separate "environment": I load some external JAR files into the class loader for some scripts, and I do not want other scripts to be able to use classes in these JARs when they are executed.
My problem is that for each script that I run, GroovyClassLoader will create a new ScriptXXXX class and load it, but never unload it.
As a result, the number of loaded classes increases indefinitely, and the memory ends up completely full.
I tried a huge number of different solutions, but no one works:
- Adding
-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC to JVM Arguments - Adding
-Dgroovy.use.classvalue=true to JVM Arguments - Removing the "metaclasses" created for each
ScriptXXXX class, as shown below: Groovy Classes are not collected, but have no evidence of a memory leak - Clearing the cache and closing
GroovyClassLoader - Using introspection to manually delete some fields that cache classes in
GroovyScriptEngineImpl - etc...
Here's the βShortest Path to the GCβ for one of the ScriptXXXX classes in Eclipse Memory Analyzer:

I clearly don't have enough solutions here, and none of them work, as the class loader always refers to classes that never get GCed.
If you want to reproduce the problem, here is a sample code:
GroovyScriptEngineImpl se; while (true) { se = new GroovyScriptEngineImpl(new GroovyClassLoader()); CompiledScript script = se.compile("println(\"hello\")"); script.eval(se.createBindings()); }
thanks
UPDATE . After reading pczeus answer, I tried to restrict metaspace, and some classes seem to really unload, and I think these are ScriptXXX classes.
However, after a few minutes I get Out of Metaspace during script execution.
Here is the profile that I get with VisualVM:

And the "Path to the GC" in the Eclipse Memory Analyzer for ScriptXXX classes ScriptXXX really empty (they are no longer an instance of classes), even if the class is still listed in the histogram.
java memory-leaks classloader groovy
Antoineb
source share