1 /* 2 * Copyright (c) 2015, 2016, 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 jdk.internal.ref; 27 28 import java.lang.ref.Cleaner; 29 import java.lang.ref.Cleaner.Cleanable; 30 import java.lang.ref.ReferenceQueue; 31 import java.util.concurrent.ThreadFactory; 32 import java.util.function.Function; 33 34 import jdk.internal.misc.InnocuousThread; 35 36 /** 37 * CleanerImpl manages a set of object references and corresponding cleaning actions. 38 * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}. 39 */ 40 public final class CleanerImpl implements Runnable { 41 private final static ThreadFactory THREAD_FACTORY = 42 new CleanerFactory.InnocuousThreadFactory(); 43 44 /** 45 * An object to access the CleanerImpl from a Cleaner; set by Cleaner init. 46 */ 47 private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null; 48 49 /** 50 * Heads of a CleanableList for each reference type. 51 */ 52 final PhantomCleanable<?> phantomCleanableList; 53 54 final WeakCleanable<?> weakCleanableList; 55 56 final SoftCleanable<?> softCleanableList; 57 58 // The ReferenceQueue of pending cleaning actions 59 final ReferenceQueue<Object> queue; 60 61 /** 62 * Called by Cleaner static initialization to provide the function 63 * to map from Cleaner to CleanerImpl. 64 * @param access a function to map from Cleaner to CleanerImpl 65 */ 66 public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) { 67 if (cleanerImplAccess == null) { 68 cleanerImplAccess = access; 69 } else { 70 throw new InternalError("cleanerImplAccess"); 71 } 72 } 73 74 /** 75 * Called to get the CleanerImpl for a Cleaner. 76 * @param cleaner the cleaner 77 * @return the corresponding CleanerImpl 78 */ 79 static CleanerImpl getCleanerImpl(Cleaner cleaner) { 80 return cleanerImplAccess.apply(cleaner); 81 } 82 83 /** 84 * Constructor for CleanerImpl. 85 */ 86 public CleanerImpl() { 87 queue = new ReferenceQueue<>(); 88 phantomCleanableList = new PhantomCleanableRef(); 89 weakCleanableList = new WeakCleanableRef(); 90 softCleanableList = new SoftCleanableRef(); 91 } 92 93 /** 94 * Starts the Cleaner implementation. 95 * Ensure this is the CleanerImpl for the Cleaner. 96 * When started waits for Cleanables to be queued. 97 * @param cleaner the cleaner 98 * @param threadFactory the thread factory 99 */ 100 public void start(Cleaner cleaner, ThreadFactory threadFactory) { 101 if (getCleanerImpl(cleaner) != this) { 102 throw new AssertionError("wrong cleaner"); 103 } 104 // schedule a nop cleaning action for the cleaner, so the associated thread 105 // will continue to run at least until the cleaner is reclaimable. 106 new CleanerCleanable(cleaner); 107 108 if (threadFactory == null) { 109 threadFactory = THREAD_FACTORY; 110 } 111 112 // now that there's at least one cleaning action, for the cleaner, 113 // we can start the associated thread, which runs until 114 // all cleaning actions have been run. 115 Thread thread = threadFactory.newThread(this); 116 thread.setDaemon(true); 117 thread.start(); 118 } 119 120 /** 121 * Process queued Cleanables as long as the cleanable lists are not empty. 122 * A Cleanable is in one of the lists for each Object and for the Cleaner 123 * itself. 124 * Terminates when the Cleaner is no longer reachable and 125 * has been cleaned and there are no more Cleanable instances 126 * for which the object is reachable. 127 * <p> 128 * If the thread is a ManagedLocalsThread, the threadlocals 129 * are erased before each cleanup 130 */ 131 @Override 132 public void run() { 133 Thread t = Thread.currentThread(); 134 InnocuousThread mlThread = (t instanceof InnocuousThread) 135 ? (InnocuousThread) t 136 : null; 137 while (!phantomCleanableList.isListEmpty() || 138 !weakCleanableList.isListEmpty() || 139 !softCleanableList.isListEmpty()) { 140 if (mlThread != null) { 141 // Clear the thread locals 142 mlThread.eraseThreadLocals(); 143 } 144 try { 145 // Wait for a Ref, with a timeout to avoid getting hung 146 // due to a race with clear/clean 147 Cleanable ref = (Cleanable) queue.remove(60 * 1000L); 148 if (ref != null) { 149 ref.clean(); 150 } 151 } catch (Throwable e) { 152 // ignore exceptions from the cleanup action 153 // (including interruption of cleanup thread) 154 } 155 } 156 } 157 158 /** 159 * Perform cleaning on an unreachable PhantomReference. 160 */ 161 public static final class PhantomCleanableRef extends PhantomCleanable<Object> { 162 private final Runnable action; 163 164 /** 165 * Constructor for a phantom cleanable reference. 166 * @param obj the object to monitor 167 * @param cleaner the cleaner 168 * @param action the action Runnable 169 */ 170 public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) { 171 super(obj, cleaner); 172 this.action = action; 173 } 174 175 /** 176 * Constructor used only for root of phantom cleanable list. 177 */ 178 PhantomCleanableRef() { 179 super(); 180 this.action = null; 181 } 182 183 @Override 184 protected void performCleanup() { 185 action.run(); 186 } 187 188 /** 189 * Prevent access to referent even when it is still alive. 190 * 191 * @throws UnsupportedOperationException always 192 */ 193 @Override 194 public Object get() { 195 throw new UnsupportedOperationException("get"); 196 } 197 198 /** 199 * Direct clearing of the referent is not supported. 200 * 201 * @throws UnsupportedOperationException always 202 */ 203 @Override 204 public void clear() { 205 throw new UnsupportedOperationException("clear"); 206 } 207 } 208 209 /** 210 * Perform cleaning on an unreachable WeakReference. 211 */ 212 public static final class WeakCleanableRef extends WeakCleanable<Object> { 213 private final Runnable action; 214 215 /** 216 * Constructor for a weak cleanable reference. 217 * @param obj the object to monitor 218 * @param cleaner the cleaner 219 * @param action the action Runnable 220 */ 221 WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) { 222 super(obj, cleaner); 223 this.action = action; 224 } 225 226 /** 227 * Constructor used only for root of weak cleanable list. 228 */ 229 WeakCleanableRef() { 230 super(); 231 this.action = null; 232 } 233 234 @Override 235 protected void performCleanup() { 236 action.run(); 237 } 238 239 /** 240 * Prevent access to referent even when it is still alive. 241 * 242 * @throws UnsupportedOperationException always 243 */ 244 @Override 245 public Object get() { 246 throw new UnsupportedOperationException("get"); 247 } 248 249 /** 250 * Direct clearing of the referent is not supported. 251 * 252 * @throws UnsupportedOperationException always 253 */ 254 @Override 255 public void clear() { 256 throw new UnsupportedOperationException("clear"); 257 } 258 } 259 260 /** 261 * Perform cleaning on an unreachable SoftReference. 262 */ 263 public static final class SoftCleanableRef extends SoftCleanable<Object> { 264 private final Runnable action; 265 266 /** 267 * Constructor for a soft cleanable reference. 268 * @param obj the object to monitor 269 * @param cleaner the cleaner 270 * @param action the action Runnable 271 */ 272 SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) { 273 super(obj, cleaner); 274 this.action = action; 275 } 276 277 /** 278 * Constructor used only for root of soft cleanable list. 279 */ 280 SoftCleanableRef() { 281 super(); 282 this.action = null; 283 } 284 285 @Override 286 protected void performCleanup() { 287 action.run(); 288 } 289 290 /** 291 * Prevent access to referent even when it is still alive. 292 * 293 * @throws UnsupportedOperationException always 294 */ 295 @Override 296 public Object get() { 297 throw new UnsupportedOperationException("get"); 298 } 299 300 /** 301 * Direct clearing of the referent is not supported. 302 * 303 * @throws UnsupportedOperationException always 304 */ 305 @Override 306 public void clear() { 307 throw new UnsupportedOperationException("clear"); 308 } 309 310 } 311 312 /** 313 * A PhantomCleanable implementation for tracking the Cleaner itself. 314 */ 315 static final class CleanerCleanable extends PhantomCleanable<Cleaner> { 316 CleanerCleanable(Cleaner cleaner) { 317 super(cleaner, cleaner); 318 } 319 320 @Override 321 protected void performCleanup() { 322 // no action 323 } 324 } 325 }