< prev index next >

src/java.base/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 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();


 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 }


  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 java.util.concurrent.ThreadLocalRandom;
  31 import sun.misc.ManagedLocalsThread;
  32 import sun.misc.SharedSecrets;
  33 import sun.misc.VM;
  34 
  35 /* Package-private; must be in same package as the Reference class */
  36 class Finalizer<T> extends FinalReference<T> implements Runnable {
  37     /**
  38      * Finalizers are registered in a doubly-linked list so that they are kept
  39      * alive until discovered by VM, processed by ReferenceHandling pool and then
  40      * unlinked. There are several lists to distribute Finalizers randomly into
  41      * to reduce contention among concurrent threads trying to link/unlink them.
  42      */
  43     static final FinalizerList[] unfinalized;
  44     static {
  45         int cpus = Runtime.getRuntime().availableProcessors();
  46         // smallest power of two equal or greater than 2 * # of CPUs
  47         int lists = (cpus <= 1) ? 2 : Integer.highestOneBit(cpus - 1) << 2;
  48         unfinalized = new FinalizerList[lists];
  49         for (int i = 0; i < lists; i++) {
  50             unfinalized[i] = new FinalizerList();







  51         }
  52     }
  53 
  54     volatile Finalizer prev;
  55     volatile Finalizer next;
  56     private final int listIndex;
  57 
  58     Finalizer(T finalizee, int listIndex) {
  59         super(finalizee, ReferenceQueue.NULL);
  60         this.listIndex = listIndex;











  61     }
  62 
  63     /** A constructor used for special Finalizer instances in FinalizerList */
  64     Finalizer() {
  65         super(null, ReferenceQueue.NULL);
  66         listIndex = -1; // never registered in any list
  67     }
  68 
  69     /** Invoked by VM for objects overriding finalize() method */
  70     static void register(Object finalizee) {
  71         int rnd = nextSecondarySeed();
  72         int index = (rnd >>> 1) & (unfinalized.length - 1);
  73         unfinalized[index].link(new Finalizer<>(finalizee, index), (rnd & 1) == 0);
  74     }
  75 
  76     @Override
  77     public void run() {
  78         T finalizee = delete();
  79         if (finalizee == null) {
  80             return;
  81         }
  82         unfinalized[listIndex].unlink(this);
  83         try {
  84             if (!(finalizee instanceof java.lang.Enum)) {
  85                 invokeFinalizee(finalizee);

  86 
  87                 /* Clear stack slot containing this variable, to decrease
  88                    the chances of false retention with a conservative GC */
  89                 finalizee = null;
  90             }
  91         } catch (Throwable x) { }
  92     }
  93 
  94     /* Invoke the finalize() method on the finalizee (overridden by Finalizator) */
  95     void invokeFinalizee(T finalizee) throws Throwable {
  96         SharedSecrets.getJavaLangAccess().invokeFinalize(finalizee);
  97         finalizee = null;
  98     }
  99 
 100     @Override
 101     public void clear() {
 102         T finalizee = delete();
 103         if (finalizee == null) {
 104             return;
 105         }
 106         unfinalized[listIndex].unlink(this);
 107         /* Clear stack slot containing this variable, to decrease
 108            the chances of false retention with a conservative GC */
 109         finalizee = null;
 110     }
 111 
 112     /* Create a privileged secondary finalizer thread in the system thread
 113            group for the given Runnable, and wait for it to complete.
 114 
 115            This method is used by both runFinalization and runFinalizersOnExit.
 116            The former method invokes all pending finalizers, while the latter
 117            invokes all uninvoked finalizers if on-exit finalization has been
 118            enabled.
 119 
 120            These two methods could have been implemented by offloading their work
 121            to the regular finalizer thread and waiting for that thread to finish.
 122            The advantage of creating a fresh thread, however, is that it insulates
 123            invokers of these methods from a stalled or deadlocked finalizer thread.
 124          */
 125     private static void forkSecondaryFinalizer(final Runnable proc) {
 126         AccessController.doPrivileged(
 127             new PrivilegedAction<>() {
 128                 public Void run() {
 129                     ThreadGroup tg = Thread.currentThread().getThreadGroup();


 136                         sft.join();
 137                     } catch (InterruptedException x) {
 138                         Thread.currentThread().interrupt();
 139                     }
 140                     return null;
 141                 }});
 142     }
 143 
 144     /* Called by Runtime.runFinalization() */
 145     static void runFinalization() {
 146         if (!VM.isBooted()) {
 147             return;
 148         }
 149 
 150         forkSecondaryFinalizer(new Runnable() {
 151             private volatile boolean running;
 152             public void run() {
 153                 // in case of recursive call to run()
 154                 if (running)
 155                     return;

 156                 running = true;
 157                 ReferenceHandling.runFinalization();




 158             }
 159         });
 160     }
 161 
 162     /* Invoked by java.lang.Shutdown */
 163     static void runAllFinalizers() {
 164         if (!VM.isBooted()) {
 165             return;
 166         }
 167 
 168         forkSecondaryFinalizer(new Runnable() {
 169             private volatile boolean running;
 170             public void run() {
 171                 // in case of recursive call to run()
 172                 if (running)
 173                     return;

 174                 running = true;
 175                 for (FinalizerList uflist : unfinalized)
 176                     for (Finalizer<?> f = uflist.first(); f != null; f = uflist.succ(f)) {
 177                         f.run();





 178                 }}});
 179     }
 180 
 181     // Unsafe mechanics
 182 
 183     /**
 184      * Returns the pseudo-randomly initialized or updated secondary seed.
 185      * Copied from ThreadLocalRandom due to package access restrictions.
 186      */
 187     static int nextSecondarySeed() {
 188         int r;
 189         Thread t = Thread.currentThread();
 190         if ((r = UNSAFE.getInt(t, threadLocalRandomSecondarySeedOffset)) != 0) {
 191             r ^= r << 13;   // xorshift
 192             r ^= r >>> 17;
 193             r ^= r << 5;
 194         }
 195         else if ((r = ThreadLocalRandom.current().nextInt()) == 0)
 196             r = 1; // avoid zero
 197         UNSAFE.putInt(t, threadLocalRandomSecondarySeedOffset, r);
 198         return r;
 199     }




 200 
 201     boolean isAlive() {
 202         return getReferentVolatile() != null;






 203     }
 204 
 205     boolean isDeleted() {
 206         return getReferentVolatile() == null;
 207     }
 208 
 209     private T delete() {
 210         T referent = getReferentVolatile();
 211         return (referent != null) && casReferent(referent, null)
 212             ? referent : null;



 213     }
 214 
 215     void lazySetNext(Finalizer<?> val) {
 216         UNSAFE.putOrderedObject(this, nextOffset, val);
 217     }
 218 
 219     boolean casNext(Finalizer<?> cmp, Finalizer<?> val) {
 220         return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
 221     }
 222 
 223     void lazySetPrev(Finalizer<?> val) {
 224         UNSAFE.putOrderedObject(this, prevOffset, val);
 225     }
 226 
 227     boolean casPrev(Finalizer<?> cmp, Finalizer<?> val) {
 228         return UNSAFE.compareAndSwapObject(this, prevOffset, cmp, val);







 229     }
 230 
 231     private static final sun.misc.Unsafe UNSAFE;
 232     private static final long prevOffset;
 233     private static final long nextOffset;
 234     private static final long threadLocalRandomSecondarySeedOffset;
 235 
 236     static {
 237         try {
 238             UNSAFE = sun.misc.Unsafe.getUnsafe();
 239             Class<Finalizer> fc = Finalizer.class;
 240             prevOffset = UNSAFE.objectFieldOffset(fc.getDeclaredField("prev"));
 241             nextOffset = UNSAFE.objectFieldOffset(fc.getDeclaredField("next"));
 242             Class<Thread> tc = Thread.class;
 243             threadLocalRandomSecondarySeedOffset = UNSAFE.objectFieldOffset
 244                 (tc.getDeclaredField("threadLocalRandomSecondarySeed"));
 245         } catch (Exception e) {
 246             throw new Error(e);
 247         }
 248     }
 249 }
< prev index next >