< prev index next >

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

Print this page




   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
  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.ManagedLocalsThread;
  32 import sun.misc.SharedSecrets;
  33 import sun.misc.VM;
  34 
  35 final class Finalizer extends FinalReference<Object> { /* Package-private; must be in
  36                                                           same package as the Reference
  37                                                           class */
  38 
  39     private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
  40     private static Finalizer unfinalized = null;
  41     private static final Object lock = new Object();
  42 
  43     private Finalizer
  44         next = null,
  45         prev = null;
  46 
  47     private boolean hasBeenFinalized() {
  48         return (next == this);
  49     }
  50 
  51     private void add() {
  52         synchronized (lock) {
  53             if (unfinalized != null) {
  54                 this.next = unfinalized;
  55                 unfinalized.prev = this;
  56             }
  57             unfinalized = this;
  58         }
  59     }
  60 
  61     private void remove() {
  62         synchronized (lock) {
  63             if (unfinalized == this) {
  64                 if (this.next != null) {
  65                     unfinalized = this.next;
  66                 } else {
  67                     unfinalized = this.prev;
  68                 }
  69             }
  70             if (this.next != null) {
  71                 this.next.prev = this.prev;
  72             }
  73             if (this.prev != null) {
  74                 this.prev.next = this.next;
  75             }
  76             this.next = this;   /* Indicates that this has been finalized */
  77             this.prev = this;
  78         }




  79     }
  80 
  81     private Finalizer(Object finalizee) {
  82         super(finalizee, queue);
  83         add();
  84     }
  85 
  86     /* Invoked by VM */
  87     static void register(Object finalizee) {
  88         new Finalizer(finalizee);

  89     }
  90 
  91     private void runFinalizer(JavaLangAccess jla) {
  92         synchronized (this) {
  93             if (hasBeenFinalized()) return;
  94             remove();

  95         }
  96         try {
  97             Object finalizee = this.get();
  98             if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
  99                 jla.invokeFinalize(finalizee);
 100 
 101                 /* Clear stack slot containing this variable, to decrease
 102                    the chances of false retention with a conservative GC */
 103                 finalizee = null;
 104             }
 105         } catch (Throwable x) { }
 106         super.clear();
 107     }
 108 
 109     /* Create a privileged secondary finalizer thread in the system thread
 110        group for the given Runnable, and wait for it to complete.
 111 
 112        This method is used by both runFinalization and runFinalizersOnExit.
 113        The former method invokes all pending finalizers, while the latter
 114        invokes all uninvoked finalizers if on-exit finalization has been
 115        enabled.
 116 
 117        These two methods could have been implemented by offloading their work
 118        to the regular finalizer thread and waiting for that thread to finish.
 119        The advantage of creating a fresh thread, however, is that it insulates
 120        invokers of these methods from a stalled or deadlocked finalizer thread.
 121      */
 122     private static void forkSecondaryFinalizer(final Runnable proc) {
 123         AccessController.doPrivileged(
 124             new PrivilegedAction<>() {
 125                 public Void run() {
 126                     ThreadGroup tg = Thread.currentThread().getThreadGroup();
 127                     for (ThreadGroup tgn = tg;


 133                         sft.join();
 134                     } catch (InterruptedException x) {
 135                         Thread.currentThread().interrupt();
 136                     }
 137                     return null;
 138                 }});
 139     }
 140 
 141     /* Called by Runtime.runFinalization() */
 142     static void runFinalization() {
 143         if (!VM.isBooted()) {
 144             return;
 145         }
 146 
 147         forkSecondaryFinalizer(new Runnable() {
 148             private volatile boolean running;
 149             public void run() {
 150                 // in case of recursive call to run()
 151                 if (running)
 152                     return;
 153                 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 154                 running = true;
 155                 for (;;) {
 156                     Finalizer f = (Finalizer)queue.poll();
 157                     if (f == null) break;
 158                     f.runFinalizer(jla);
 159                 }
 160             }
 161         });
 162     }
 163 
 164     /* Invoked by java.lang.Shutdown */
 165     static void runAllFinalizers() {
 166         if (!VM.isBooted()) {
 167             return;
 168         }
 169 
 170         forkSecondaryFinalizer(new Runnable() {
 171             private volatile boolean running;
 172             public void run() {
 173                 // in case of recursive call to run()
 174                 if (running)
 175                     return;
 176                 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 177                 running = true;
 178                 for (;;) {
 179                     Finalizer f;
 180                     synchronized (lock) {
 181                         f = unfinalized;
 182                         if (f == null) break;
 183                         unfinalized = f.next;
 184                     }
 185                     f.runFinalizer(jla);
 186                 }}});
 187     }
 188 
 189     private static class FinalizerThread extends ManagedLocalsThread {
 190         private volatile boolean running;
 191         FinalizerThread(ThreadGroup g) {
 192             super(g, "Finalizer");





 193         }
 194         public void run() {
 195             // in case of recursive call to run()
 196             if (running)
 197                 return;
 198 
 199             // Finalizer thread starts before System.initializeSystemClass
 200             // is called.  Wait until JavaLangAccess is available
 201             while (!VM.isBooted()) {
 202                 // delay until VM completes initialization
 203                 try {
 204                     VM.awaitBooted();
 205                 } catch (InterruptedException x) {
 206                     // ignore and continue






 207                 }



 208             }
 209             final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
 210             running = true;
 211             for (;;) {
 212                 try {
 213                     Finalizer f = (Finalizer)queue.remove();
 214                     f.runFinalizer(jla);
 215                 } catch (InterruptedException x) {
 216                     // ignore and continue
 217                 }



 218             }



 219         }



 220     }
 221 
 222     static {
 223         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 224         for (ThreadGroup tgn = tg;
 225              tgn != null;
 226              tg = tgn, tgn = tg.getParent());
 227         Thread finalizer = new FinalizerThread(tg);
 228         finalizer.setPriority(Thread.MAX_PRIORITY - 2);
 229         finalizer.setDaemon(true);
 230         finalizer.start();
 231     }
 232 
















 233 }


   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
  23  * questions.
  24  */
  25 
  26 package java.lang.ref;
  27 



  28 import sun.misc.ManagedLocalsThread;
  29 import sun.misc.SharedSecrets;
  30 import sun.misc.VM;
  31 
  32 import java.security.AccessController;
  33 import java.security.PrivilegedAction;





  34 
  35 /* Package-private; must be in same package as the Reference class */
  36 class Finalizer<T> extends FinalReference<T> implements Cleaner {

  37 
  38     Finalizer(T finalizee) {
  39         super(finalizee, null);
  40     }
  41 
  42     /** Invoked by VM for objects overriding finalize() method */
  43     static void register(Object finalizee) {
  44         Finalizer<?> finalizer = new Finalizer<>(finalizee);
  45         finalizer.link();




  46     }
  47 
  48     @Override
  49     public void clean() {
  50         T finalizee = delete();
  51         if (finalizee == null) {
  52             return;












  53         }
  54         unlink();
  55         try {
  56             if (!(finalizee instanceof java.lang.Enum)) {
  57                 invokeFinalizee(finalizee);
  58             }
  59         } catch (Throwable x) { }
  60         finalizee = null;


  61     }
  62 
  63     /* Invoke the finalize() method on the finalizee (overridden by Finalizator) */
  64     void invokeFinalizee(T finalizee) throws Throwable {
  65         SharedSecrets.getJavaLangAccess().invokeFinalize(finalizee);
  66         finalizee = null;
  67     }
  68 
  69     @Override
  70     public void clear() {
  71         T finalizee = delete();
  72         if (finalizee == null) {
  73             return;
  74         }
  75         unlink();




  76         /* Clear stack slot containing this variable, to decrease
  77            the chances of false retention with a conservative GC */
  78         finalizee = null;
  79     }



  80 
  81     /* Create a privileged secondary finalizer thread in the system thread
  82        group for the given Runnable, and wait for it to complete.
  83 
  84        This method is used by both runFinalization and runFinalizersOnExit.
  85        The former method invokes all pending finalizers, while the latter
  86        invokes all uninvoked finalizers if on-exit finalization has been
  87        enabled.
  88 
  89        These two methods could have been implemented by offloading their work
  90        to the regular finalizer thread and waiting for that thread to finish.
  91        The advantage of creating a fresh thread, however, is that it insulates
  92        invokers of these methods from a stalled or deadlocked finalizer thread.
  93      */
  94     private static void forkSecondaryFinalizer(final Runnable proc) {
  95         AccessController.doPrivileged(
  96             new PrivilegedAction<>() {
  97                 public Void run() {
  98                     ThreadGroup tg = Thread.currentThread().getThreadGroup();
  99                     for (ThreadGroup tgn = tg;


 105                         sft.join();
 106                     } catch (InterruptedException x) {
 107                         Thread.currentThread().interrupt();
 108                     }
 109                     return null;
 110                 }});
 111     }
 112 
 113     /* Called by Runtime.runFinalization() */
 114     static void runFinalization() {
 115         if (!VM.isBooted()) {
 116             return;
 117         }
 118 
 119         forkSecondaryFinalizer(new Runnable() {
 120             private volatile boolean running;
 121             public void run() {
 122                 // in case of recursive call to run()
 123                 if (running)
 124                     return;

 125                 running = true;
 126                 ReferenceHandling.runFinalization();




 127             }
 128         });
 129     }
 130 
 131     /* Invoked by java.lang.Shutdown */
 132     static void runAllFinalizers() {
 133         if (!VM.isBooted()) {
 134             return;
 135         }
 136 
 137         forkSecondaryFinalizer(new Runnable() {
 138             private volatile boolean running;
 139             public void run() {
 140                 // in case of recursive call to run()
 141                 if (running)
 142                     return;

 143                 running = true;
 144                 for (DLList ucList : uncleanedLists)
 145                     for (Reference<?> f = ucList.first(); f != null; f = ucList.succ(f)) {
 146                         ((Cleaner)f).clean();





 147                 }}});
 148     }
 149 
 150     /**
 151      * Atomically clear the Finalizer and return the finalizee.
 152      *
 153      * @return the finalizee or null
 154      */
 155     private T delete() {
 156         T referent = getReferentVolatile();
 157         return (referent != null) && casReferent(referent, null)
 158                ? referent : null;
 159     }




 160 
 161     // Methods and state that enable Finalizer to be an element of DLList
 162 
 163     /** A constructor used for special Reference instances used in DLList */
 164     Finalizer(boolean setPrevToSelf, boolean setNextToSelf) {
 165         super(null, null);
 166         if (setPrevToSelf) prevDll = this;
 167         if (setNextToSelf) nextDll = this;
 168     }
 169 
 170     @SuppressWarnings("unused") // assigned through Unsafe
 171     private volatile Reference<?> prevDll, nextDll;
 172 
 173     boolean isDeletedDll() {
 174         return getReferentVolatile() == null;
 175     }
 176 
 177     Reference<?> getPrevDll() {
 178         return prevDll;
 179     }
 180 
 181     void lazySetPrevDll(Reference<?> val) {
 182         UNSAFE.putOrderedObject(this, PREV_DLL, val);





 183     }
 184 
 185     boolean casPrevDll(Reference<?> cmp, Reference<?> val) {
 186         return UNSAFE.compareAndSwapObject(this, PREV_DLL, cmp, val);
 187     }
 188 
 189     Reference<?> getNextDll() {
 190         return nextDll;
 191     }
 192 
 193     void lazySetNextDll(Reference<?> val) {
 194         UNSAFE.putOrderedObject(this, NEXT_DLL, val);
 195     }
 196 
 197     boolean casNextDll(Reference<?> cmp, Reference<?> val) {
 198         return UNSAFE.compareAndSwapObject(this, NEXT_DLL, cmp, val);







 199     }
 200 
 201     // Unsafe machinery
 202 
 203     private static final sun.misc.Unsafe UNSAFE;
 204     private static final long PREV_DLL;
 205     private static final long NEXT_DLL;
 206 
 207     static {
 208         try {
 209             UNSAFE = sun.misc.Unsafe.getUnsafe();
 210             Class<Finalizer> fc = Finalizer.class;
 211             PREV_DLL = UNSAFE.objectFieldOffset(fc.getDeclaredField("prevDll"));
 212             NEXT_DLL = UNSAFE.objectFieldOffset(fc.getDeclaredField("nextDll"));
 213         } catch (Exception e) {
 214             throw new Error(e);
 215         }
 216     }
 217 }
< prev index next >