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 40 /** Head of doubly linked list of Finalizers awaiting finalization. */ 41 private static Finalizer unfinalized = null; 42 43 /** Lock guarding access to unfinalized list. */ 44 private static final Object lock = new Object(); 45 46 private Finalizer next, prev; 47 48 private Finalizer(Object finalizee) { 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 }