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

Class.forName causes memory leak

XMLWordPrintable

    • b140
    • x86_64
    • windows_7
    • Verified

        FULL PRODUCT VERSION :
        java version "1.8.0_73"
        Java(TM) SE Runtime Environment (build 1.8.0_73-b02)
        Java HotSpot(TM) 64-Bit Server VM (build 25.73-b02, mixed mode)

        ADDITIONAL OS VERSION INFORMATION :
        Microsoft Windows [version 6.1.7601]


        A DESCRIPTION OF THE PROBLEM :
        Class.forName use with Classloader.getSystemClassLoader and policy and security manager activated provoke a memory leak.

        REGRESSION. Last worked in version 8u66

        ADDITIONAL REGRESSION INFORMATION:
        Don't know exactly the version.
        On Mac OS X it works with 1.6.0_65 and 1.8.0_05.

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Compile the 2 classes with a maven project
        java -jar target/classfornameleak-0.0.1-SNAPSHOT.jar

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        classloader name: leaked classloader
        OK no bug
        ACTUAL -
        classloader name: leaked classloader
        Not yet GC
        Not yet GC
        Not yet GC
        Not yet GC
        Not yet GC
        ...

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        package classfornameleak;

        import java.util.List;


        public class ClassForName implements Runnable {

            public void run() {
                System.out.println("classloader name: " + ClassForName.class.getClassLoader());
                try {
                    Class.forName(List.class.getName(), false, ClassLoader.getSystemClassLoader());
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }

        }


        -----------


        package classfornameleak;

        import java.io.File;
        import java.io.FileOutputStream;
        import java.io.InputStream;
        import java.lang.ref.WeakReference;
        import java.net.URL;
        import java.net.URLClassLoader;
        import java.security.Permission;
        import java.security.Policy;
        import java.security.ProtectionDomain;
        import java.util.jar.JarOutputStream;
        import java.util.zip.ZipEntry;

        public class ClassForNameLeak {

            public static WeakReference<ClassLoader> init() throws Exception {
                System.setSecurityManager(new SecurityManager() {
                    @Override
                    public void checkPermission(final Permission perm) {
                        return;
                    }
                });
                Policy.setPolicy(new Policy() {
                    @Override
                    public boolean implies(final ProtectionDomain domain, final Permission permission) {
                        return true;
                    }
                });

                URL resource = ClassForNameLeak.class.getResource("ClassForName.class");
                File jarFile = File.createTempFile("cfn", ".jar");
                JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(jarFile));
                jarFile.deleteOnExit();

                ZipEntry zipEntry = new ZipEntry("classfornameleak/");
                jarOutputStream.putNextEntry(zipEntry);

                zipEntry = new ZipEntry("classfornameleak/ClassForName.class");
                byte[] buffer = new byte[1024];
                InputStream openStream = resource.openStream();

                jarOutputStream.putNextEntry(zipEntry);
                while (true) {
                    int count = openStream.read(buffer);
                    if (count == -1) {
                        break;
                    }
                    jarOutputStream.write(buffer, 0, count);
                }
                jarOutputStream.closeEntry();
                jarOutputStream.close();

                ClassLoader classLoader = new URLClassLoader(new URL[] {jarFile.toURI().toURL()}) {

                    @Override
                    public Class<?> loadClass(final String name) throws ClassNotFoundException {
                        if (ClassForName.class.getName().equals(name)) {
                            return findClass(name);
                        }
                        return super.loadClass(name);
                    }

                    @Override
                    public String toString() {
                        return "leaked classloader";
                    }
                };

                Class<?> loadClass = classLoader.loadClass(ClassForName.class.getName());
                ((Runnable) loadClass.newInstance()).run();
                return new WeakReference<ClassLoader>(classLoader);
            }

            public static void main(final String[] args) throws Exception {
                WeakReference<ClassLoader> weakReference = init();

                for (int i = 0; i < 10; i++) {
                    System.gc();
                }
                while (weakReference.get() != null) {
                    System.out.println("Not yet GC");
                    System.gc();
                    Thread.sleep(100);
                }

                System.out.println("OK no bug");

            }

        }


        ------------------

        <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
          <groupId>classfornameleak</groupId>
          <artifactId>classfornameleak</artifactId>
          <version>0.0.1-SNAPSHOT</version>
          <build>
            <plugins>
              <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                  <archive>
                    <manifest>
                      <mainClass>classfornameleak.ClassForNameLeak</mainClass>
                    </manifest>
                  </archive>
                </configuration>
              </plugin>
            </plugins>
          </build>
        </project>
        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        Not found

              bchristi Brent Christian
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              9 Start watching this issue

                Created:
                Updated:
                Resolved: