[ 
https://issues.apache.org/jira/browse/GROOVY-6655?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17279197#comment-17279197
 ] 

João Paulo commented on GROOVY-6655:
------------------------------------

I have found a workaround for this problem: 
https://issues.apache.org/jira/browse/GROOVY-8113?focusedCommentId=17279013&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-17279013

> GroovyClassLoader parallelLockMap memory leak on Java 7
> -------------------------------------------------------
>
>                 Key: GROOVY-6655
>                 URL: https://issues.apache.org/jira/browse/GROOVY-6655
>             Project: Groovy
>          Issue Type: Bug
>          Components: groovy-runtime
>    Affects Versions: 2.2.2
>         Environment: Java 7
>            Reporter: Henri Pihkala
>            Priority: Critical
>              Labels: classloader, java, leak, memory, metaprogramming
>
> Java 7 introduced parallel classloading. There is a map in 
> {{java.lang.ClassLoader}} called {{parallelLockMap}}. This map holds String 
> keys for class names and the associated Objects used to synchronize on for 
> each class.
> Now, I found that dynamically parsing (perhaps also loading?) and unloading 
> classes with {{GroovyClassLoader}} leaves obsolete keys in this map. Any time 
> {{java.lang.ClassLoader#loadClass(..)}} is called, an entry is created for 
> that class name if it does not exist. 
> In the default Java delegating classloader paradigm the delegate classloader 
> is asked for a class first, so a call to the root loader's 
> {{java.lang.ClassLoader#loadClass(..)}} is made for a whole lot of classes, 
> including Groovy metaclasses, polluting the map with keys.
> !https://dl.dropboxusercontent.com/u/4655232/parallelLockMapMemoryLeak.png!
> The entries that remain in the map even after the class and associated 
> metaclasses themselves have been unloaded have the following two types of 
> keys:
> {{"groovy.runtime.metaclass.MyDynamicallyLoadedClassNameMetaClass"}}
> {{"MyDynamicallyLoadedClassNameBeanInfo"}}
> A key for the class name itself, ie. {{MyDynamicallyLoadedClassName}}, does 
> not appear in the map. I am assuming it is never inserted there, but instead 
> defined by {{GroovyClassLoader}} without asking the parent first. But these 
> metaclass keys *do* leak into the map, eventually exhausting heap memory even 
> if the classes themselves get nicely unloaded (from PermGen) when the 
> {{GroovyClassLoader}} is GC'ed.
> Here's a very simple test script that will eventually run out of memory (it 
> does take some time):
> {code:title=MemoryLeakTest.groovy}
>     String newClass = "class CLASSNAME {}"
>     while (true) {
>         GroovyClassLoader gcl = new GroovyClassLoader()
>         Class clazz = gcl.parseClass(newClass.replace("CLASSNAME", 
> "NewClass"+System.nanoTime()))
>         clazz.newInstance()
>     }
> {code}
> Be sure to run JVM with
> {noformat}
> -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
> {noformat}
> to make sure you run out of *heap* memory and not *PermGen* space.
> One fix for this would be to add a check to {{GroovyClassLoader}} that would 
> prevent it from delegating to the parent first if the class to be loaded is a 
> metaclass of a class loaded by that classloader. I am definitely no expert in 
> this so you might come up with a much better idea.
> This has been tested on Groovy 2.0.5 and 2.2.2 and I expect that it affects a 
> lot of versions running on Java 7.
> Sure, it doesn't leak memory at a very fast pace, only a 
> {{ConcurrentHashMap}} entry for each class loaded and unloaded. I can see how 
> in many applications this is not a major problem, but please consider for 
> example a server that automatically checks students' programming assignments 
> or such. Please do change the issue priority if appropriate.
> !https://dl.dropboxusercontent.com/u/4655232/parallelLockMapMemoryLeak2.png!



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to