You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Craig (JIRA)" <ji...@apache.org> on 2015/10/09 22:31:05 UTC

[jira] [Updated] (GROOVY-6704) Memory leak in ClassInfo when using MetaClasses

     [ https://issues.apache.org/jira/browse/GROOVY-6704?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Craig updated GROOVY-6704:
--------------------------
    Attachment: MyClassValue.java
                CVTest.java

I also really dislike the Oracle issue tracker... you can't even watch issues (nevermind add comments) unless you have an account, and it seems like very few people are eligible for accounts.

Still doesn't run:
{noformat}
Exception in thread "main" java.lang.IllegalAccessError: tried to access class Dummy from class MyClassValue
	at MyClassValue.computeValue(MyClassValue.java:6)
	at java.lang.ClassValue.getFromHashMap(ClassValue.java:227)
	at java.lang.ClassValue.getFromBackup(ClassValue.java:209)
	at java.lang.ClassValue.get(ClassValue.java:115)
	at CVTest.main(CVTest.java:13)
{noformat}

By changing Dummy to an inner class, I can make it run. I've attached [^CVTest.java] and [^MyClassValue.java]

Here's what I did:
$ javac MyClassValue.java && javac CVTest.java && jar cvf t/t.jar MyClassValue*.class && rm MyClassValue*.class && JAVA_OPTS=-Xmx4m java CVTest

After a while (~20 minutes) I got this error:
{noformat}
Exception in thread "main" java.lang.OutOfMemoryError: Compressed class space
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
	at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at CVTest.main(CVTest.java:12)
{noformat}
So I guess that's the test case and resulting proof for JDK-8136353

> Memory leak in ClassInfo when using MetaClasses
> -----------------------------------------------
>
>                 Key: GROOVY-6704
>                 URL: https://issues.apache.org/jira/browse/GROOVY-6704
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 2.0.8, 2.1.9
>            Reporter: Craig
>            Assignee: Jochen Theodorou
>            Priority: Critical
>             Fix For: 2.4.0-beta-2
>
>         Attachments: CVTest.java, LeakTest.groovy, MyClassValue.java
>
>
> I'm trying to track down a memory leak in Grails and I'm pretty sure I've discovered the root cause of the leak is in Groovy. For reference, here's the thread on the grails-dev list on this topic: http://grails.1312388.n4.nabble.com/Easily-reproducible-memory-leak-in-Grails-td4655816.html
> I also raised this issue on the groovy-dev mailing list at http://groovy.329449.n5.nabble.com/Memory-leak-in-ClassInfo-when-using-MetaClasses-td5719218.html
> The problem is that when a class is loaded, then a metaclass is assigned, then the class is no longer reachable, the metaclass remains in memory. When this happens many times, lots of metaclasses are leaked, which becomes a significant problem. I discovered this problem because this how Grails implements GSPs - by loading the GSP as a groovy class, then when the GSP changes, loading a new class. The old class is unreachable, except for some internal Groovy structures... hence the memory leak.
> Attached there is a junit test that reproduces this problem: [^LeakTest.groovy]
> Eventually, that results in an OutOfMemoryError. Using a tool like visualvm, it is clear that the number of classes constantly rises, none are ever unloaded, and the permgen keeps getting used. The heap also rises. In my tests, it usually dies after about 5,000 iterations.
> In my opinion, this shouldn't happen - this test case should run without leaking memory. Groovy should allow the MetaClasses to be garbage collected once the Class is no longer referenced by anything else. In other words, Groovy should hold a weak reference to the MetaClass/ClassInfo/etc for the Class based on the reachability of the Class.
> By taking a heap dump in visualvm, I found that there are lots of instances of org.codehaus.groovy.runtime.metaclass.MetaMethodIndex$Entry.
> The problem areas (that are GC roots) seem to be:
> org.codehaus.groovy.reflection.ClassInfo's static field modifiedExpandos
> org.codehaus.groovy.reflection.ClassInfo's static field globalClassSet
> The classes that area created by classLoader.parseClass also stick around, which is why the permgen is leaking.
> Can someone please help me determine how to fix this problem in Groovy?



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)