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 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 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 the 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 that method 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 }