Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6916498

Class loader leak goes unreported via JVMTI

    XMLWordPrintable

    Details

    • Subcomponent:
      gc
    • CPU:
      x86
    • OS:
      solaris_8

      Description

      FULL PRODUCT VERSION :
      Java(TM) SE Runtime Environment (build 1.6.0_17-b04)
      Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01, mixed mode

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [Version 5.2.3790]
      Windows XP, 64-bit, SP2

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      Not applicable

      A DESCRIPTION OF THE PROBLEM :
      The context class loader during the first call to DocumentBuilderFactory.newInstance().newDocumentBuilder() is pinned into memory but the details of what is pinning the class loader are not available via the JVMTI interface.

      This frequently occurs in servlet containers and can result in a significant memory leak on web application reload.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Execute the code provided below with whatever settings are required by your profiler of choice (I used YourKit)
      2. Connect the profiler
      3. Force GC
      4. Check the instances of URLClassLoader present
      5. Trigger a heap dump
      6. Trace the GC roots of any URLClassLoader

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The expected result when a profiler is attached is that, after forcing GC, there are zero instances of URLClassLoader present.
      ACTUAL -
      The actual result when a profiler is attached is that, after forcing GC, there is one instance of URLClassLoader present. No GC Roots are reported for this object (checked with multiple profilers including JHat) but the object is never GC'd. This creates a memory leak.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package org.apache.markt;

      import javax.xml.parsers.DocumentBuilderFactory;
      import javax.xml.parsers.ParserConfigurationException;
      import java.lang.reflect.Method;
      import java.net.URLClassLoader;

      public final class ClassLoaderLeak {
        public static void main(final String[] args) throws Exception {
          createLoader();

          System.in.read(); // capture snapshot at this point
        }

        public static void foo() {
          try {
            DocumentBuilderFactory.newInstance().newDocumentBuilder();
          }
          catch (ParserConfigurationException ignored) {
              // Ignore
          }
        }

        private static void createLoader() throws Exception {
          final ClassLoader myLoader = new URLClassLoader(
            ((URLClassLoader)ClassLoader.getSystemClassLoader()).getURLs(),
            null
          );
          // load some class
          final Class<?> aClass = myLoader.loadClass(ClassLoaderLeak.class.getName());
          final Method method = aClass.getDeclaredMethod("foo", new Class<?>[]{});
          method.invoke(null, new Object[]{});
        }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      The workaround is to force DocumentBuilderFactory.newInstance().newDocumentBuilder() to be called from a class loader that is not expected to be GC'd.

        Attachments

          Activity

            People

            Assignee:
            mcastegr Mattis Castegren (Inactive)
            Reporter:
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: