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

(refs) Calling a synchronized method from finalize() can lock VM

    • 1.2alpha2
    • x86, sparc
    • solaris_2.5.1, solaris_2.6, windows_95, windows_nt
    • Not verified



      Name: joT67522 Date: 11/11/97


      /******

      PROBLEM: Synchronously running the finalizer thread can cause deadlock
         The finalizer and VM memory allocator can cause system deadlock under the following conditions:
         1 - a finalize method calls a synchronized method
         2 - a synchronized method which will block the finalize method in 1 causes an allocation failure
         3 - the garbage collector tries to flush the finalizer queue
         4 - the method from 1 blocks waiting on 2 (which is waiting on 1)
           DEADLOCK

      Environment: Java_1_1_final on NT4.0
      NOTE: also reproduced on 1.1.3

      MAJOR ISSUES:
      This kind of problem comes up in the following real world scenario:
      A missed ResultSet.close() results in the following sequence of calls:
      sun.jdbc.odbc.JdbcResultSet.finalize()
      sun.jdbc.odbc.JdbcResultSet.close()
      sun.jdbc.odbc.JdbcOdbc.SQLFreeStatment() { which is synchronized }

      ****/

      // a sample class to replicate VM GC lockup problem -- let it run for a little while
      public class GCLock
      {
      public static void main(String[] argv)
      {
      GCLock factory = new GCLock();

      factory.make();
      }

      public GCLock()
      {
      storage = new String[10];

      allocateStorage();

      System.out.print(".");
      }

      // keep creating objects with no references -- throw them away
      public void make()
      {
      while(true)
      {
      new GCLock();
      }
      }

      public void finalize()
      {
      System.out.print("/");

      // call a synchronized "method"
      releaseStorage();

      System.out.print("\\");
      }

      private String[] storage;
      private static Object allocator = new Object();

      private void allocateStorage()
      {
      synchronized(allocator)
      {
      // spend some time inside a synchronized block that
      for (int i = 0; i < storage.length; i++)
      storage[i] =
      new String("Now is the time for all good men to come to the aid of their country.");
      }
      }

      private void releaseStorage()
      {
      synchronized(allocator)
      {
      storage = null;
      }
      }

      }

      /****************************
       Below is the output of the above class run on NT4.0 - java 1.1_Final
      ........................................................................................................................
      ........................................................................................................................
      ........................................................................................................................
      ............................................................................./\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
      \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
      \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
      \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
      \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
      \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
      \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
      \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\.............
      ........................................................................................................................
      ........................................................................................................................
      ........................................................................................................................
      .............................................................../

      ****** at this point the VM is locked up tight as a drum. NO OTHER THREADS WILL RUN!!!!

      Full thread dump:
          "Finalizer thread" (TID:0xf500d0, sys_thread_t:0x87b680, Win32ID:0xc4, state:MW) prio=2
              GCLock.releaseStorage(GCLock.java:54)
              GCLock.finalize(GCLock.java:33)
          "main" (TID:0xf500a8, sys_thread_t:0x87bca0, Win32ID:0xc1, state:CW) prio=5
              java.lang.String.<init>(String.java:124)
              GCLock.allocateStorage(GCLock.java:48)
              GCLock.<init>(GCLock.java:14)
              GCLock.make(GCLock.java:24)
              GCLock.main(GCLock.java:7)
      Monitor Cache Dump:
               java.lang.Object@F536E0/F9D190 (key=0xf536e0): "main"
      Registered Monitor Dump:
          Thread queue lock: <unowned>
          Name and type hash table lock: <unowned>
          String intern lock: <unowned>
          JNI global reference lock: <unowned>
          BinClass lock: <unowned>
          Class loading lock: <unowned>
          Java stack lock: <unowned>
          Code rewrite lock: <unowned>
          Heap lock: <unowned>
          Has finalization queue lock: <unowned>
          Finalize me queue lock: <unowned>
              waiters = 1
          Monitor cache expansion lock: <unowned>
          Monitor registry: <unowned>
      /*******/

      company - LPA Software Inc. , email - ###@###.###
      (Review ID: 13650)
      ======================================================================

      The problematic finalize() method for us is ColorModel.finalize(). By looking at the stack traces for our deadlock cases (one of which is pasted below), it shows that this method is executing in the finalizer thread, and that it is waiting for a monitor lock on an instance of sun.awt.image.PixelStore8, which is already owned by the image fetching thread.
      Therefore, let me outline the exact steps that are producing our deadlock, using the steps listed above:
      1 - The image fetching thread obtains the monitor lock for an instance of sun.awt.image.PixelStore8, and then causes an allocation failure.
      2 - the garbage collector tries to flush the finalizer queue.
      3 - ColorModel.finalize(), via its calling chain, attempts to obtain the monitor lock for the sun.awt.image.PixelStore8 instance that is already being held in 1.
      4 - the finalizer thread from 3 blocks waiting on 1 (which is waiting on 3)
      DEADLOCK

            mr Mark Reinhold
            johsunw Joon Oh (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: