In an application, I repeatedly create instances of GroovyShell and execute custom scripts on them. When doing this, I experience problems that the perm gen space in Java 6 and Java 7 is filling up and classes are not unloaded. I am using Groovy 2.4.7. The problem can be reproduced with the following code:
import groovy.lang.GroovyShell;
public class Demo {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10000000; i++) {
GroovyShell gs = new GroovyShell();
Object result = gs.evaluate(" 'Hello, World';");
assert result.equals("Hello, World");
}
}
}
I am using the following VM arguments:
-verbose:class -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+CMSClassUnloadingEnabled -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -XX:+TraceClassUnloading -XX:MaxPermSize=16M -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:+PrintGCDetails -XX:-UseParNewGC
When I execute the test from above, the PermGen is full after a little over 2000 iterations. Also, triggering the GC manually does not work.
Is there any way to force class unloading here or trigger the GC so that the classes are removed from PermGen space?
Woah. Hold up. I just gave this one a quick shot and it seems to work perfectly. Instead of using the shell directly, though, you compile a script and then run the script (for the same outcome). Then call the specified cleaner.
Obviously you could optimize the cleaner a bit to eliminate a bunch of reflection.
PermGen is pretty flat:
And classes are being unloaded at a brisk pace:
Credit to @BilboDai.