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

URLClassLoader.findClass does not properly close Resource, leading to potential leak

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      Linux Mint 22
      JAVA11

      A DESCRIPTION OF THE PROBLEM :
      When loading classes through java.net.URLClassLoader#findClass in JDK 11, the internal implementation obtains a Resource instance from URLClassPath.getResource(), but the resource is not explicitly closed after use.

      As a result, when the class data is read from a JAR entry or a compressed resource, the associated ZipInflaterInputStream and its native inflater buffers may remain unclosed until GC finalization.
      This can cause off-heap (native) memory leaks and delayed resource cleanup, especially in long-running applications that dynamically load and unload classes or modules via multiple URLClassLoader instances.

      The relevant code path (from URLClassLoader#findClass) looks like:

      result = AccessController.doPrivileged(
          new PrivilegedExceptionAction<>() {
              public Class<?> run() throws ClassNotFoundException {
                  String path = name.replace('.', '/').concat(".class");
                  Resource res = ucp.getResource(path, false);
                  if (res != null) {
                      try {
                          return defineClass(name, res);
                      } catch (IOException e) {
                          throw new ClassNotFoundException(name, e);
                      } catch (ClassFormatError e2) {
                          if (res.getDataError() != null) {
                              e2.addSuppressed(res.getDataError());
                          }
                          throw e2;
                      }
                  } else {
                      return null;
                  }
              }
          }, acc);


      Here, res is never closed after defineClass(name, res) returns.
      If res internally opens a ZipEntry or InflaterInputStream, the native Inflater may hold memory until it is finalized, leading to continuous native memory growth and potential OutOfMemoryError: Direct buffer memory or OutOfMemoryError: Java heap space depending on allocator pressure.

      Expected behavior:

      Resource should be closed (or at least its stream released) after successful or failed class definition to ensure deterministic cleanup of underlying native structures.

      Environment:

      JDK 11 (and possibly later)

      Observed on Linux x86_64

      Reproducible in long-running class reloading scenarios (e.g., dynamic plugin systems)

      Possible fix:

      Ensure that Resource (and its underlying stream) is closed in a finally block after defineClass(...) completes, similar to how resource handling is managed elsewhere in the JDK.

      REGRESSION : Last worked in version 11

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      just look it

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Need to close the resource immediately
      ACTUAL -
      Not closed in a timely manner

            jpai Jaikiran Pai
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: