Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Memory leaks #52

Merged
merged 4 commits into from
Feb 22, 2015
Merged

Memory leaks #52

merged 4 commits into from
Feb 22, 2015

Conversation

jglick
Copy link
Member

@jglick jglick commented Feb 18, 2015

When running a flow repeatedly, the WorkflowScript (a dynamic CpsScript subclass) is not promptly collected, nor is its GroovyClassLoader.InnerLoader and thus an assortment of derivative classes and objects. Demo:

jmap -histo $pid | fgrep WorkflowScript | wc -l

prints the number of builds you have just run. (Note that each line is a class called WorkflowScript from its own class loader.)

I think I have fixed all the hard-reference leaks, so Jenkins will collect the remaining SoftReferences under heavy memory pressure rather than throwing an OutOfMemoryError; to demo, using the current patch run in /script

for (i = 1; ; i *= 2) {
  System.gc();
  new Object[i];
}

and the WorkflowScript count will drop to 0. Sometimes this also happens after merely

System.gc();

But in the meantime the heap (or in Java 6/7, permanent generation) slowly grows.

@reviewbybees (ref. ZD-24759)

@stephenc
Copy link
Member

(checkpoint) changes so far look ok to me, but I lack the context to be certain

@jglick
Copy link
Member Author

jglick commented Feb 19, 2015

Actually not looking too bad at the moment in Java 8. If I set the job to rebuild itself repeatedly (once per second), and monitor the class count, it climbs to around 50–60 before spontaneously clearing.

The ClassInfo leak in detail, from MAT:

Class Name                                                                                             | Ref. Objects | Shallow Heap | Ref. Shallow Heap | Retained Heap
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
java.lang.Thread @ 0x708730d28  Computer.threadPoolForRemoting [#5] Native Stack, Thread               |           16 |          120 |               768 |         3,504
'- contextClassLoader org.jenkinsci.maven.plugins.hpi.RunMojo$2 @ 0x7075d4208  /jenkins                |           16 |           96 |               768 |     2,002,944
   '- classes java.util.Vector @ 0x7075e15a0                                                           |           16 |           32 |               768 |     1,701,504
      '- elementData java.lang.Object[5120] @ 0x707878848                                              |           16 |       20,496 |               768 |     1,701,472
         '- [3552] class org.codehaus.groovy.reflection.ClassInfo @ 0x7079139a0                        |           16 |           24 |               768 |           232
            '- globalClassSet org.codehaus.groovy.reflection.ClassInfo$ClassInfoSet @ 0x707913a38      |           16 |           32 |               768 |           112
               '- segments org.codehaus.groovy.util.AbstractConcurrentMapBase$Segment[16] @ 0x707913a58|           16 |           80 |               768 |            80
                  |- [15] org.codehaus.groovy.reflection.ClassInfo$ClassInfoSet$Segment @ 0x707913aa8  |            1 |           48 |                48 |       828,488
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

or from VisualVM:

this     - value: groovy.lang.GroovyClassLoader$InnerLoader #18
 <- <classLoader>     - class: WorkflowScript, value: groovy.lang.GroovyClassLoader$InnerLoader #18
  <- referent     - class: org.codehaus.groovy.util.ReferenceType$SoftRef, value: WorkflowScript class WorkflowScript
   <- ref     - class: org.codehaus.groovy.reflection.ClassInfo, value: org.codehaus.groovy.util.ReferenceType$SoftRef #2309
    <- [30]     - class: java.lang.Object[], value: org.codehaus.groovy.reflection.ClassInfo #462
     <- table     - class: org.codehaus.groovy.reflection.ClassInfo$ClassInfoSet$Segment, value: java.lang.Object[] #46259
      <- segment     - class: org.codehaus.groovy.reflection.ClassInfo, value: org.codehaus.groovy.reflection.ClassInfo$ClassInfoSet$Segment #13
       <- classInfo     - class: org.codehaus.groovy.reflection.stdclasses.ArrayCachedClass, value: org.codehaus.groovy.reflection.ClassInfo #151
        <- ARR_CLASS     - class: org.codehaus.groovy.runtime.dgmimpl.arrays.IntegerArrayGetAtMetaMethod, value: org.codehaus.groovy.reflection.stdclasses.ArrayCachedClass #11

@jglick
Copy link
Member Author

jglick commented Feb 20, 2015

Java 7 shows the same behavior of WorkflowScript count resetting to 0. However the number of InnerLoaders continues to increase and the permanent generation steadily grows until I force an OutOfMemoryError.

@jglick
Copy link
Member Author

jglick commented Feb 20, 2015

On a lark I tried

org.codehaus.groovy.util.ReferenceBundle.softBundle.type = org.codehaus.groovy.util.ReferenceBundle.weakBundle.type

but it does not seem to help.

@jglick
Copy link
Member Author

jglick commented Feb 20, 2015

Well even on Java 7 (u67) the permanent generation does apparently get collected if you are just patient enough; takes around 1000 InnerLoaders before that happens, but over time I get a sawtooth curve on the PermGen graph, with cycles around every 15 minutes on my machine. So I think I am declaring victory for now.

@tfennelly
Copy link
Member

So the main thing so far has been the upgrade of groovy-cpsand the use of org.jboss.marshalling.reflect.SerializableClassRegistry and java.beans.Introspector to clean out the classes loaded by the script classloader?

@jglick
Copy link
Member Author

jglick commented Feb 20, 2015

And clearing the shell field after the build finishes.

@jglick jglick changed the title [WiP] Memory leaks Memory leaks Feb 21, 2015
@jglick
Copy link
Member Author

jglick commented Feb 22, 2015

@reviewbybees ready to merge from my perspective.

@tfennelly
Copy link
Member

👍

@jglick jglick merged commit 3e4c9c1 into jenkinsci:master Feb 22, 2015
jglick added a commit that referenced this pull request Feb 22, 2015
@jglick jglick deleted the memory-leaks branch February 22, 2015 21:50
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants