The GroovySystem is a class that resides in the AppClassLoader. It's final and only contains static attributes and methods.
Inside it, we find a MetaClassRegistry static property, that is initialized with a MetaClassRegistryImpl instance.
The MetaClassRegistryImpl contains a ConcurrentReaderHashMap wich holds references to all Expando classes, and metaclasses.
And that's the problem. Since the ExpandoClasses and MetaClasses are usually created via script by a GroovyClassLoader, this map prevents them be garbage collected, as well as its GroovyClassLoader.
In our application, we use a schema similar to a web server. We create a different class loader for each executed script. This is necessary since users want to modificate scripts and see the results imediatelly. We've even tried to use the GroovyScriptEngine in the past, but it has a very big flaw. its performance is terrible in a network (I even opened another issue for this). Also, we like the benefit of having a different class loader per script, since we may have different execution environments.
As a result, we are suffering the "the dreaded "java.lang.OutOfMemoryError: PermGen space" exception", as described in this article:
To simulate the problem, run the above java program with -Xmx500m option:
It uses this script:
The problem will occur after 7000 executions. In this sample, we need 500Mb heap, otherwise, the heap space will go out of memory before the permgen space. But in our real situation (with bigger classes, and more classes in the class loader) 200Mb heap is enough, since the permgen space is consumed faster.