src/share/classes/java/lang/ref/Finalizer.java

Print this page




  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.ref;
  27 
  28 import java.security.PrivilegedAction;
  29 import java.security.AccessController;
  30 


  31 
  32 final class Finalizer extends FinalReference<Object> { /* Package-private; must be in
  33                                                           same package as the Reference
  34                                                           class */
  35 
  36     /* A native method that invokes an arbitrary object's finalize method is
  37        required since the finalize method is protected
  38      */
  39     static native void invokeFinalizeMethod(Object o) throws Throwable;
  40 
  41     private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
  42     private static Finalizer unfinalized = null;
  43     private static final Object lock = new Object();
  44 
  45     private Finalizer
  46         next = null,
  47         prev = null;
  48 
  49     private boolean hasBeenFinalized() {
  50         return (next == this);
  51     }
  52 
  53     private void add() {
  54         synchronized (lock) {
  55             if (unfinalized != null) {
  56                 this.next = unfinalized;
  57                 unfinalized.prev = this;
  58             }
  59             unfinalized = this;
  60         }


  73                 this.next.prev = this.prev;
  74             }
  75             if (this.prev != null) {
  76                 this.prev.next = this.next;
  77             }
  78             this.next = this;   /* Indicates that this has been finalized */
  79             this.prev = this;
  80         }
  81     }
  82 
  83     private Finalizer(Object finalizee) {
  84         super(finalizee, queue);
  85         add();
  86     }
  87 
  88     /* Invoked by VM */
  89     static void register(Object finalizee) {
  90         new Finalizer(finalizee);
  91     }
  92 
  93     private void runFinalizer() {
  94         synchronized (this) {
  95             if (hasBeenFinalized()) return;
  96             remove();
  97         }
  98         try {
  99             Object finalizee = this.get();
 100             if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
 101                 invokeFinalizeMethod(finalizee);

 102                 /* Clear stack slot containing this variable, to decrease
 103                    the chances of false retention with a conservative GC */
 104                 finalizee = null;
 105             }
 106         } catch (Throwable x) { }
 107         super.clear();
 108     }
 109 
 110     /* Create a privileged secondary finalizer thread in the system thread
 111        group for the given Runnable, and wait for it to complete.
 112 
 113        This method is used by both runFinalization and runFinalizersOnExit.
 114        The former method invokes all pending finalizers, while the latter
 115        invokes all uninvoked finalizers if on-exit finalization has been
 116        enabled.
 117 
 118        These two methods could have been implemented by offloading their work
 119        to the regular finalizer thread and waiting for that thread to finish.
 120        The advantage of creating a fresh thread, however, is that it insulates
 121        invokers of these methods from a stalled or deadlocked finalizer thread.


 124         AccessController.doPrivileged(
 125             new PrivilegedAction<Void>() {
 126                 public Void run() {
 127                 ThreadGroup tg = Thread.currentThread().getThreadGroup();
 128                 for (ThreadGroup tgn = tg;
 129                      tgn != null;
 130                      tg = tgn, tgn = tg.getParent());
 131                 Thread sft = new Thread(tg, proc, "Secondary finalizer");
 132                 sft.start();
 133                 try {
 134                     sft.join();
 135                 } catch (InterruptedException x) {
 136                     /* Ignore */
 137                 }
 138                 return null;
 139                 }});
 140     }
 141 
 142     /* Called by Runtime.runFinalization() */
 143     static void runFinalization() {





 144         forkSecondaryFinalizer(new Runnable() {
 145             private volatile boolean running;
 146             public void run() {
 147                 if (running)
 148                     return;
 149                 running = true;
 150                 for (;;) {
 151                     Finalizer f = (Finalizer)queue.poll();
 152                     if (f == null) break;
 153                     f.runFinalizer();
 154                 }
 155             }
 156         });
 157     }
 158 
 159     /* Invoked by java.lang.Shutdown */
 160     static void runAllFinalizers() {





 161         forkSecondaryFinalizer(new Runnable() {
 162             private volatile boolean running;
 163             public void run() {
 164                 if (running)
 165                     return;
 166                 running = true;
 167                 for (;;) {
 168                     Finalizer f;
 169                     synchronized (lock) {
 170                         f = unfinalized;
 171                         if (f == null) break;
 172                         unfinalized = f.next;
 173                     }
 174                     f.runFinalizer();
 175                 }}});
 176     }
 177 
 178     private static class FinalizerThread extends Thread {
 179         private volatile boolean running;
 180         FinalizerThread(ThreadGroup g) {
 181             super(g, "Finalizer");
 182         }
 183         public void run() {
 184             if (running)
 185                 return;












 186             running = true;
 187             for (;;) {
 188                 try {
 189                     Finalizer f = (Finalizer)queue.remove();
 190                     f.runFinalizer();
 191                 } catch (InterruptedException x) {
 192                     continue;
 193                 }
 194             }
 195         }
 196     }
 197 
 198     static {
 199         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 200         for (ThreadGroup tgn = tg;
 201              tgn != null;
 202              tg = tgn, tgn = tg.getParent());
 203         Thread finalizer = new FinalizerThread(tg);
 204         finalizer.setPriority(Thread.MAX_PRIORITY - 2);
 205         finalizer.setDaemon(true);
 206         finalizer.start();
 207     }
 208 
 209 }


  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.ref;
  27 
  28 import java.security.PrivilegedAction;
  29 import java.security.AccessController;
  30 import sun.misc.JavaLangAccess;
  31 import sun.misc.SharedSecrets;
  32 import sun.misc.VM;
  33 
  34 final class Finalizer extends FinalReference<Object> { /* Package-private; must be in
  35                                                           same package as the Reference
  36                                                           class */
  37 





  38     private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
  39     private static Finalizer unfinalized = null;
  40     private static final Object lock = new Object();
  41 
  42     private Finalizer
  43         next = null,
  44         prev = null;
  45 
  46     private boolean hasBeenFinalized() {
  47         return (next == this);
  48     }
  49 
  50     private void add() {
  51         synchronized (lock) {
  52             if (unfinalized != null) {
  53                 this.next = unfinalized;
  54                 unfinalized.prev = this;
  55             }
  56             unfinalized = this;
  57         }


  70                 this.next.prev = this.prev;
  71             }
  72             if (this.prev != null) {
  73                 this.prev.next = this.next;
  74             }
  75             this.next = this;   /* Indicates that this has been finalized */
  76             this.prev = this;
  77         }
  78     }
  79 
  80     private Finalizer(Object finalizee) {
  81         super(finalizee, queue);
  82         add();
  83     }
  84 
  85     /* Invoked by VM */
  86     static void register(Object finalizee) {
  87         new Finalizer(finalizee);
  88     }
  89 
  90     private void runFinalizer(JavaLangAccess jla) {
  91         synchronized (this) {
  92             if (hasBeenFinalized()) return;
  93             remove();
  94         }
  95         try {
  96             Object finalizee = this.get();
  97             if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
  98                 jla.invokeFinalize(finalizee);
  99 
 100                 /* Clear stack slot containing this variable, to decrease
 101                    the chances of false retention with a conservative GC */
 102                 finalizee = null;
 103             }
 104         } catch (Throwable x) { }
 105         super.clear();
 106     }
 107 
 108     /* Create a privileged secondary finalizer thread in the system thread
 109        group for the given Runnable, and wait for it to complete.
 110 
 111        This method is used by both runFinalization and runFinalizersOnExit.
 112        The former method invokes all pending finalizers, while the latter
 113        invokes all uninvoked finalizers if on-exit finalization has been
 114        enabled.
 115 
 116        These two methods could have been implemented by offloading their work
 117        to the regular finalizer thread and waiting for that thread to finish.
 118        The advantage of creating a fresh thread, however, is that it insulates
 119        invokers of these methods from a stalled or deadlocked finalizer thread.


 122         AccessController.doPrivileged(
 123             new PrivilegedAction<Void>() {
 124                 public Void run() {
 125                 ThreadGroup tg = Thread.currentThread().getThreadGroup();
 126                 for (ThreadGroup tgn = tg;
 127                      tgn != null;
 128                      tg = tgn, tgn = tg.getParent());
 129                 Thread sft = new Thread(tg, proc, "Secondary finalizer");
 130                 sft.start();
 131                 try {
 132                     sft.join();
 133                 } catch (InterruptedException x) {
 134                     /* Ignore */
 135                 }
 136                 return null;
 137                 }});
 138     }
 139 
 140     /* Called by Runtime.runFinalization() */
 141     static void runFinalization() {
 142         if (!VM.isBooted()) {
 143             return;
 144         }
 145         
 146         final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 147         forkSecondaryFinalizer(new Runnable() {
 148             private volatile boolean running;
 149             public void run() {
 150                 if (running)
 151                     return;
 152                 running = true;
 153                 for (;;) {
 154                     Finalizer f = (Finalizer)queue.poll();
 155                     if (f == null) break;
 156                     f.runFinalizer(jla);
 157                 }
 158             }
 159         });
 160     }
 161 
 162     /* Invoked by java.lang.Shutdown */
 163     static void runAllFinalizers() {
 164         if (!VM.isBooted()) {
 165             return;
 166         }
 167 
 168         final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 169         forkSecondaryFinalizer(new Runnable() {
 170             private volatile boolean running;
 171             public void run() {
 172                 if (running)
 173                     return;
 174                 running = true;
 175                 for (;;) {
 176                     Finalizer f;
 177                     synchronized (lock) {
 178                         f = unfinalized;
 179                         if (f == null) break;
 180                         unfinalized = f.next;
 181                     }
 182                     f.runFinalizer(jla);
 183                 }}});
 184     }
 185 
 186     private static class FinalizerThread extends Thread {
 187         private volatile boolean running;
 188         FinalizerThread(ThreadGroup g) {
 189             super(g, "Finalizer");
 190         }
 191         public void run() {
 192             if (running)
 193                 return;
 194 
 195             // Finalizer thread starts before System.initializeSystemClass 
 196             // is called.  Wait until JavaLangAccess is available
 197             while (!VM.isBooted()) {
 198                 // delay until VM completes initialization
 199                 try {
 200                     VM.awaitBooted();
 201                 } catch (InterruptedException x) {
 202                     // ignore and continue
 203                 }
 204             }
 205             final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 206             running = true;
 207             for (;;) {
 208                 try {
 209                     Finalizer f = (Finalizer)queue.remove();
 210                     f.runFinalizer(jla);
 211                 } catch (InterruptedException x) {
 212                     // ignore and continue
 213                 }
 214             }
 215         }
 216     }
 217 
 218     static {
 219         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 220         for (ThreadGroup tgn = tg;
 221              tgn != null;
 222              tg = tgn, tgn = tg.getParent());
 223         Thread finalizer = new FinalizerThread(tg);
 224         finalizer.setPriority(Thread.MAX_PRIORITY - 2);
 225         finalizer.setDaemon(true);
 226         finalizer.start();
 227     }
 228 
 229 }