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