< prev index next >

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

Print this page


   1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  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


  49         super(finalizee, queue);
  50         // push onto unfinalized
  51         synchronized (lock) {
  52             if (unfinalized != null) {
  53                 this.next = unfinalized;
  54                 unfinalized.prev = this;
  55             }
  56             unfinalized = this;
  57         }
  58     }
  59 
  60     static ReferenceQueue<Object> getQueue() {
  61         return queue;
  62     }
  63 
  64     /* Invoked by VM */
  65     static void register(Object finalizee) {
  66         new Finalizer(finalizee);
  67     }
  68 
  69     private void deregisterAndRunFinalizer(JavaLangAccess jla) {
  70         synchronized (lock) {
  71             if (this.next == this)      // already finalized
  72                 return;
  73             // unlink from unfinalized
  74             if (unfinalized == this)
  75                 unfinalized = this.next;
  76             else
  77                 this.prev.next = this.next;
  78             if (this.next != null)
  79                 this.next.prev = this.prev;
  80             this.prev = null;
  81             this.next = this;           // mark as finalized
  82         }
  83         runFinalizer(jla);
  84     }
  85 
  86     private void runFinalizer(JavaLangAccess jla) {
  87         try {
  88             Object finalizee = this.get();
  89             if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
  90                 jla.invokeFinalize(finalizee);
  91 
  92                 /* Clear stack slot containing this variable, to decrease
  93                    the chances of false retention with a conservative GC */
  94                 finalizee = null;
  95             }
  96         } catch (Throwable x) { }
  97         super.clear();
  98     }
  99 
 100     /* Create a privileged secondary finalizer thread in the system thread
 101        group for the given Runnable, and wait for it to complete.
 102 
 103        This method is used by both runFinalization and runFinalizersOnExit.
 104        The former method invokes all pending finalizers, while the latter
 105        invokes all uninvoked finalizers if on-exit finalization has been
 106        enabled.
 107 
 108        These two methods could have been implemented by offloading their work
 109        to the regular finalizer thread and waiting for that thread to finish.
 110        The advantage of creating a fresh thread, however, is that it insulates
 111        invokers of these methods from a stalled or deadlocked finalizer thread.
 112      */
 113     private static void forkSecondaryFinalizer(final Runnable proc) {
 114         AccessController.doPrivileged(
 115             new PrivilegedAction<>() {
 116                 public Void run() {
 117                     ThreadGroup tg = Thread.currentThread().getThreadGroup();
 118                     for (ThreadGroup tgn = tg;
 119                          tgn != null;
 120                          tg = tgn, tgn = tg.getParent());
 121                     Thread sft = new Thread(tg, proc, "Secondary finalizer", 0, false);
 122                     sft.start();
 123                     try {
 124                         sft.join();
 125                     } catch (InterruptedException x) {
 126                         Thread.currentThread().interrupt();
 127                     }
 128                     return null;
 129                 }});
 130     }
 131 
 132     /* Called by Runtime.runFinalization() */
 133     static void runFinalization() {
 134         if (VM.initLevel() == 0) {
 135             return;
 136         }
 137 
 138         forkSecondaryFinalizer(new Runnable() {
 139             private volatile boolean running;
 140             public void run() {
 141                 // in case of recursive call to run()
 142                 if (running)
 143                     return;
 144                 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 145                 running = true;
 146                 for (Finalizer f; (f = (Finalizer)queue.poll()) != null; )
 147                     f.deregisterAndRunFinalizer(jla);
 148             }
 149         });
 150     }
 151 
 152     /* Invoked by java.lang.Shutdown */
 153     static void runAllFinalizers() {
 154         if (VM.initLevel() == 0) {
 155             return;
 156         }
 157 
 158         forkSecondaryFinalizer(new Runnable() {
 159             private volatile boolean running;
 160             public void run() {
 161                 // in case of recursive call to run()
 162                 if (running)
 163                     return;
 164                 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 165                 running = true;
 166                 for (;;) {
 167                     // "pollFirst" from unfinalized
 168                     Finalizer f;
 169                     synchronized (lock) {
 170                         f = unfinalized;
 171                         if (f == null) break;
 172                         unfinalized = f.next;
 173                         if (unfinalized != null)
 174                             unfinalized.prev = null;
 175                         f.next = f; // mark as finalized
 176                     }
 177                     f.runFinalizer(jla);
 178                 }}});
 179     }
 180 
 181     private static class FinalizerThread extends Thread {
 182         private volatile boolean running;
 183         FinalizerThread(ThreadGroup g) {
 184             super(g, null, "Finalizer", 0, false);
 185         }
 186         public void run() {
 187             // in case of recursive call to run()
 188             if (running)
 189                 return;
 190 
 191             // Finalizer thread starts before System.initializeSystemClass
 192             // is called.  Wait until JavaLangAccess is available
 193             while (VM.initLevel() == 0) {
 194                 // delay until VM completes initialization
 195                 try {
 196                     VM.awaitInitLevel(1);
 197                 } catch (InterruptedException x) {
 198                     // ignore and continue
 199                 }
 200             }
 201             final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 202             running = true;
 203             for (;;) {
 204                 try {
 205                     Finalizer f = (Finalizer)queue.remove();
 206                     f.deregisterAndRunFinalizer(jla);
 207                 } catch (InterruptedException x) {
 208                     // ignore and continue
 209                 }
 210             }
 211         }
 212     }
 213 
 214     static {
 215         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 216         for (ThreadGroup tgn = tg;
 217              tgn != null;
 218              tg = tgn, tgn = tg.getParent());
 219         Thread finalizer = new FinalizerThread(tg);
 220         finalizer.setPriority(Thread.MAX_PRIORITY - 2);
 221         finalizer.setDaemon(true);
 222         finalizer.start();
 223     }
 224 
 225 }
   1 /*
   2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  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


  49         super(finalizee, queue);
  50         // push onto unfinalized
  51         synchronized (lock) {
  52             if (unfinalized != null) {
  53                 this.next = unfinalized;
  54                 unfinalized.prev = this;
  55             }
  56             unfinalized = this;
  57         }
  58     }
  59 
  60     static ReferenceQueue<Object> getQueue() {
  61         return queue;
  62     }
  63 
  64     /* Invoked by VM */
  65     static void register(Object finalizee) {
  66         new Finalizer(finalizee);
  67     }
  68 
  69     private void runFinalizer(JavaLangAccess jla) {
  70         synchronized (lock) {
  71             if (this.next == this)      // already finalized
  72                 return;
  73             // unlink from unfinalized
  74             if (unfinalized == this)
  75                 unfinalized = this.next;
  76             else
  77                 this.prev.next = this.next;
  78             if (this.next != null)
  79                 this.next.prev = this.prev;
  80             this.prev = null;
  81             this.next = this;           // mark as finalized
  82         }


  83 

  84         try {
  85             Object finalizee = this.get();
  86             if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
  87                 jla.invokeFinalize(finalizee);
  88 
  89                 // Clear stack slot containing this variable, to decrease
  90                 // the chances of false retention with a conservative GC
  91                 finalizee = null;
  92             }
  93         } catch (Throwable x) { }
  94         super.clear();
  95     }
  96 
  97     /* Create a privileged secondary finalizer thread in the system thread
  98      * group for the given Runnable, and wait for it to complete.
  99      *
 100      * This method is used by runFinalization.
 101      *
 102      * It could have been implemented by offloading their work to the
 103      * regular finalizer thread and waiting for that thread to finish.
 104      * The advantage of creating a fresh thread, however, is that it insulates
 105      * invokers of these methods from a stalled or deadlocked finalizer thread.



 106      */
 107     private static void forkSecondaryFinalizer(final Runnable proc) {
 108         AccessController.doPrivileged(
 109             new PrivilegedAction<>() {
 110                 public Void run() {
 111                     ThreadGroup tg = Thread.currentThread().getThreadGroup();
 112                     for (ThreadGroup tgn = tg;
 113                          tgn != null;
 114                          tg = tgn, tgn = tg.getParent());
 115                     Thread sft = new Thread(tg, proc, "Secondary finalizer", 0, false);
 116                     sft.start();
 117                     try {
 118                         sft.join();
 119                     } catch (InterruptedException x) {
 120                         Thread.currentThread().interrupt();
 121                     }
 122                     return null;
 123                 }});
 124     }
 125 
 126     /* Called by Runtime.runFinalization() */
 127     static void runFinalization() {
 128         if (VM.initLevel() == 0) {
 129             return;
 130         }
 131 
 132         forkSecondaryFinalizer(new Runnable() {
 133             private volatile boolean running;
 134             public void run() {
 135                 // in case of recursive call to run()
 136                 if (running)
 137                     return;
 138                 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 139                 running = true;
 140                 for (Finalizer f; (f = (Finalizer)queue.poll()) != null; )
 141                     f.runFinalizer(jla);
 142             }
 143         });
 144     }
 145 





























 146     private static class FinalizerThread extends Thread {
 147         private volatile boolean running;
 148         FinalizerThread(ThreadGroup g) {
 149             super(g, null, "Finalizer", 0, false);
 150         }
 151         public void run() {
 152             // in case of recursive call to run()
 153             if (running)
 154                 return;
 155 
 156             // Finalizer thread starts before System.initializeSystemClass
 157             // is called.  Wait until JavaLangAccess is available
 158             while (VM.initLevel() == 0) {
 159                 // delay until VM completes initialization
 160                 try {
 161                     VM.awaitInitLevel(1);
 162                 } catch (InterruptedException x) {
 163                     // ignore and continue
 164                 }
 165             }
 166             final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 167             running = true;
 168             for (;;) {
 169                 try {
 170                     Finalizer f = (Finalizer)queue.remove();
 171                     f.runFinalizer(jla);
 172                 } catch (InterruptedException x) {
 173                     // ignore and continue
 174                 }
 175             }
 176         }
 177     }
 178 
 179     static {
 180         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 181         for (ThreadGroup tgn = tg;
 182              tgn != null;
 183              tg = tgn, tgn = tg.getParent());
 184         Thread finalizer = new FinalizerThread(tg);
 185         finalizer.setPriority(Thread.MAX_PRIORITY - 2);
 186         finalizer.setDaemon(true);
 187         finalizer.start();
 188     }
 189 
 190 }
< prev index next >