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 23 * questions. 24 */ 25 26 package java.lang.ref; 27 28 import java.security.PrivilegedAction; 29 import java.security.AccessController; 30 import jdk.internal.misc.JavaLangAccess; 31 import jdk.internal.misc.SharedSecrets; 32 import jdk.internal.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 } 58 } 59 60 private void remove() { 61 synchronized (lock) { 62 if (unfinalized == this) { 63 if (this.next != null) { 64 unfinalized = this.next; 65 } else { 66 unfinalized = this.prev; 67 } 68 } 69 if (this.next != null) { 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 static ReferenceQueue<Object> getQueue() { 86 return queue; 87 } 88 89 /* Invoked by VM */ 90 static void register(Object finalizee) { 91 new Finalizer(finalizee); 92 } 93 94 private void runFinalizer(JavaLangAccess jla) { 95 synchronized (this) { 96 if (hasBeenFinalized()) return; 97 remove(); 98 } 99 try { 100 Object finalizee = this.get(); 101 if (finalizee != null && !(finalizee instanceof java.lang.Enum)) { 102 jla.invokeFinalize(finalizee); 103 104 /* Clear stack slot containing this variable, to decrease 105 the chances of false retention with a conservative GC */ 106 finalizee = null; 107 } 108 } catch (Throwable x) { } 109 super.clear(); 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(); 130 for (ThreadGroup tgn = tg; 131 tgn != null; 132 tg = tgn, tgn = tg.getParent()); 133 Thread sft = new Thread(tg, proc, "Secondary finalizer", 0, false); 134 sft.start(); 135 try { 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.initLevel() == 0) { 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 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); 157 running = true; 158 for (;;) { 159 Finalizer f = (Finalizer)queue.poll(); 160 if (f == null) break; 161 f.runFinalizer(jla); 162 } 163 } 164 }); 165 } 166 167 /* Invoked by java.lang.Shutdown */ 168 static void runAllFinalizers() { 169 if (VM.initLevel() == 0) { 170 return; 171 } 172 173 forkSecondaryFinalizer(new Runnable() { 174 private volatile boolean running; 175 public void run() { 176 // in case of recursive call to run() 177 if (running) 178 return; 179 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); 180 running = true; 181 for (;;) { 182 Finalizer f; 183 synchronized (lock) { 184 f = unfinalized; 185 if (f == null) break; 186 unfinalized = f.next; 187 } 188 f.runFinalizer(jla); 189 }}}); 190 } 191 192 private static class FinalizerThread extends Thread { 193 private volatile boolean running; 194 FinalizerThread(ThreadGroup g) { 195 super(g, null, "Finalizer", 0, false); 196 } 197 public void run() { 198 // in case of recursive call to run() 199 if (running) 200 return; 201 202 // Finalizer thread starts before System.initializeSystemClass 203 // is called. Wait until JavaLangAccess is available 204 while (VM.initLevel() == 0) { 205 // delay until VM completes initialization 206 try { 207 VM.awaitInitLevel(1); 208 } catch (InterruptedException x) { 209 // ignore and continue 210 } 211 } 212 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); 213 running = true; 214 for (;;) { 215 try { 216 Finalizer f = (Finalizer)queue.remove(); 217 f.runFinalizer(jla); 218 } catch (InterruptedException x) { 219 // ignore and continue 220 } 221 } 222 } 223 } 224 225 static { 226 ThreadGroup tg = Thread.currentThread().getThreadGroup(); 227 for (ThreadGroup tgn = tg; 228 tgn != null; 229 tg = tgn, tgn = tg.getParent()); 230 Thread finalizer = new FinalizerThread(tg); 231 finalizer.setPriority(Thread.MAX_PRIORITY - 2); 232 finalizer.setDaemon(true); 233 finalizer.start(); 234 } 235 236 }