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

URLClassLoader will not GC if loaded class registers shutdown hook

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 1.4.0
    • core-libs
    • None
    • x86
    • windows_nt


      FULL OPERATING SYSTEM VERSION :

      Microsoft Windows 2000 [Version 5.00.2195]

      ADDITIONAL OPERATING SYSTEMS :

      all platforms we tested exhibit this problem, including
      Windows 98, Windows NT/2000, Solaris 7, Redhat Linux

      A DESCRIPTION OF THE PROBLEM :
      If a shutdown hook is registered by calling
      Runtime.addShutdownHook(), and the Thread registered is an
      instance of a class loaded by a URLClassLoader, the
      URLClassLoader will never be garbage collected, even if the
      shutdown hook is de-registered by calling
      Runtime.removeShutdownHook() and all other references to
      objects of classes loaded by this URLClassLoader are
      released.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Compile the test programs listed below
      (URLClassLoaderBug.java and Stupid.java)
      2. Jar up URLClassLoaderBug.class into URLClassLoaderBug.jar
      3. Jar up Stupid.class into stupid.jar
      4. Run:
      java -classpath URLClassLoaderBug.jar URLClassLoaderBug
      stupid.jar Stupid


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      The test program "Starter" takes two arguments: a jar file
      name and a class name. It builds a URL for the based on the
      Jar file name, instantiates a URLClassLoader, loads the
      requested class from the URLClassLoader, creates a new
      thread to launch the process, sets the thread context class
      loader, and runs the thread. I subclassed URLClassLoader
      and implemented finalize() so that I know when it gets
      garbage collected.

      The test program "Stupid" just prints out some text, and
      registers and deregisters a shutdown hook.

      When I use "Starter" to run "Stupid", I expect that the
      URLClassLoader used to isolate Stupid will be garbage
      collected after "Stupid" exits. However, this never occurs.

      Note: I had some problems getting garbage collection to run
      immediately. I actually ran this program in JProbe and that
      was able to force garbage collection.

      If you comment out the code in Stupid.java that registers
      the shutdown hook, the URLClassLoader will get garbage
      collected.

      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      Starter.java:
      --------------------------------------
      import java.net.URL;
      import java.io.File;
      import java.net.URLClassLoader;
      import java.lang.reflect.Method;

      public class Starter
      {

          public class MyURLClassLoader extends URLClassLoader
          {
      public MyURLClassLoader(URL[] classpath)
      {
      super(classpath, ClassLoader.getSystemClassLoader());
      }

      protected void finalize()
      {
      System.out.println("MyURLClassLoader.finalize()");
      }
          }

          public class MainThread extends Thread
          {
      private Method mainMethod;
      public MainThread(Method mainMethod)
      {
      this.mainMethod = mainMethod;
      }

      public void run()
      {
      try
      {
      mainMethod.invoke(null, new Object[] {new String[0]});
      }
      catch (Throwable e)
      {
      e.printStackTrace();
      }
      }
          }

          public Starter(String jarFilename, String className)
      throws Exception
          {
      File jarFile = new File(jarFilename);

      URL jarURL = jarFile.toURL();

      MyURLClassLoader classLoader = new MyURLClassLoader(new
      URL[] {jarURL});

      Class targetClass = classLoader.loadClass(className);
      Class[] arg_types = { String[].class };
      Method mainMethod = targetClass.getMethod("main", arg_types);

      Thread mainThread = new MainThread(mainMethod);
      mainThread.setContextClassLoader(classLoader);

      mainThread.start();
      mainThread.join();
      System.out.println("Main Method of " + className + " exited");
          }

          public static void main(String[] args) throws Exception
          {
      new Starter(args[0], args[1]);
      System.gc();
      System.in.read(); // block until user hits return
          }
      }

      -------------------------------------------
      Stupid.java:
      -------------------------------------------
      public class Stupid
      {
          public Stupid() throws Exception
          {
      Thread shutdownHook = new Thread()
      {
      public void run()
      {
      System.out.println("This is a stupid shutdown hook");
      }
      };
      Runtime.getRuntime().addShutdownHook(shutdownHook);
      Runtime.getRuntime().removeShutdownHook(shutdownHook);
          }

          public static void main(String[] args) throws Exception
          {
      System.out.println("This is a stupid program");
      new Stupid();
      System.out.println("This has been a stupid program");
          }
      }

            mr Mark Reinhold
            cprasadsunw Ck Prasad (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: