If you take a look at the dump here: https://dl.dropboxusercontent.com/u/20288797/temp/memory-dump.tar.bz2
And that you look at the classes, you will see several copies of the class
org.codenarc.rule.Violationor
org.codehaus.groovy.antlr.parser.GroovyLexer`. The multiple copies come from different classloaders, which is fine.
What is not is that those classes are not retained anymore, nor is their classloader (they are all softly or weakly reachable),
but they are not garbage collected, leading to the leak.
To reproduce the PermGen leak, first make sure you use JDK 7 or JDK 6, but the two should be tested independently because Groovy doesn't use the same way to store global class information (ClassValue since JDK 7).
- Checkout this branch: https://github.com/melix/gradle/tree/cc-oom-codenarc
- Compile a local version of Gradle that includes the changes in that branch:
./gradlew clean install -Pgradle_installPath=/path/to/local/gradle/build
- Execute the failing integration test using that local version of Gradle
JAVA_HOME=/opt/jdk1.7.0_75 /path/to/local/gradle/build/bin/gradle reporting:intTest --tests org.gradle.api.reporting.plugins.BuildDashboardPluginIntegrationTest
It will fail with an OutOfMemoryError (PermGen space).
The test has been manually updated to fail early, but it happens without modifications of the code base too. It seems to
be related to CodeNarc (problem shows up starting from CodeNarc 0.23) and Gradle 2.3+. It is going worse starting from
Groovy 2.4.4 compared to Groovy 2.3.10, but we already rules Groovy out of the game, because the OOM occurs even with 2.3.10.
I have made some changes to org.gradle.api.internal.project.DefaultIsolatedAntBuilder
which is where we create multiple
classloaders which have different goals, but the idea is to have a separate classloader for each Ant execution task with
a given classpath. Those classloaders are supposed to be cached, but I disabled caching temporarily to put this out of
the game.
I am afraid your tool lied to you. In your dump I have searched for
org.codenarc.rule.Violation
class. It is loaded by 3 class loaders. And every one of them is strongly reachable from GC roots via multiple paths. Here is the example: