1090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/* 2090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Copyright (C) 2007 Google Inc. 3090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 4090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * you may not use this file except in compliance with the License. 6090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * You may obtain a copy of the License at 7090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 8090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 10090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * See the License for the specific language governing permissions and 14090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * limitations under the License. 15090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 16090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 17090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonpackage com.google.common.base; 18090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 19090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.io.FileNotFoundException; 20090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.io.IOException; 21090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.lang.ref.Reference; 22090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.lang.ref.ReferenceQueue; 23090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.lang.reflect.Method; 24090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.net.URL; 25090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.net.URLClassLoader; 26090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.logging.Level; 27090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.logging.Logger; 28090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 29090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/** 30090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * A reference queue with an associated background thread that dequeues 31090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * references and invokes {@link FinalizableReference#finalizeReferent()} on 32090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * them. 33090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 34090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * <p>Keep a strong reference to this object until all of the associated 35090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * referents have been finalized. If this object is garbage collected earlier, 36090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * the backing thread will not invoke {@code finalizeReferent()} on the 37090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * remaining references. 38090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 39090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @author Bob Lee 40bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library) 41090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 42090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonpublic class FinalizableReferenceQueue { 43090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 44090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /* 45090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * The Finalizer thread keeps a phantom reference to this object. When the 46090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * client (ReferenceMap, for example) no longer has a strong reference to 47090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * this object, the garbage collector will reclaim it and enqueue the 48090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * phantom reference. The enqueued reference will trigger the Finalizer to 49090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * stop. 50090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 51090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * If this library is loaded in the system class loader, 52090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * FinalizableReferenceQueue can load Finalizer directly with no problems. 53090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 54090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * If this library is loaded in an application class loader, it's important 55090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * that Finalizer not have a strong reference back to the class loader. 56090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Otherwise, you could have a graph like this: 57090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 58090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Finalizer Thread 59090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * runs instance of -> Finalizer.class 60090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * loaded by -> Application class loader 61090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * which loaded -> ReferenceMap.class 62090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * which has a static -> FinalizableReferenceQueue instance 63090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 64090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Even if no other references to classes from the application class loader 65090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * remain, the Finalizer thread keeps an indirect strong reference to the 66090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * queue in ReferenceMap, which keeps the Finalizer running, and as a result, 67090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * the application class loader can never be reclaimed. 68090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 69090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * This means that dynamically loaded web applications and OSGi bundles can't 70090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * be unloaded. 71090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 72090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * If the library is loaded in an application class loader, we try to break 73090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * the cycle by loading Finalizer in its own independent class loader: 74090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 75090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * System class loader 76090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * -> Application class loader 77090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * -> ReferenceMap 78090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * -> FinalizableReferenceQueue 79090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * -> etc. 80090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * -> Decoupled class loader 81090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * -> Finalizer 82090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 83090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Now, Finalizer no longer keeps an indirect strong reference to the 84090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * static FinalizableReferenceQueue field in ReferenceMap. The application 85090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * class loader can be reclaimed at which point the Finalizer thread will 86090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * stop and its decoupled class loader can also be reclaimed. 87090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 88090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * If any of this fails along the way, we fall back to loading Finalizer 89090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * directly in the application class loader. 90090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 91090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 92090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private static final Logger logger 93090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson = Logger.getLogger(FinalizableReferenceQueue.class.getName()); 94090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 95090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private static final String FINALIZER_CLASS_NAME 96090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson = "com.google.common.base.internal.Finalizer"; 97090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 98090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** Reference to Finalizer.startFinalizer(). */ 99090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private static final Method startFinalizer; 100090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson static { 101090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Class<?> finalizer = loadFinalizer( 102090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson new SystemLoader(), new DecoupledLoader(), new DirectLoader()); 103090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson startFinalizer = getStartFinalizer(finalizer); 104090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 105090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 106090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 107090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * The actual reference queue that our background thread will poll. 108090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 109090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson final ReferenceQueue<Object> queue; 110090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 111090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 112090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Whether or not the background thread started successfully. 113090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 114090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson final boolean threadStarted; 115090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 116090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 117090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Constructs a new queue. 118090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 119090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @SuppressWarnings("unchecked") 120090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public FinalizableReferenceQueue() { 121090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // We could start the finalizer lazily, but I'd rather it blow up early. 122090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson ReferenceQueue<Object> queue; 123090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson boolean threadStarted = false; 124090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson try { 125090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson queue = (ReferenceQueue<Object>) startFinalizer.invoke(null, 126090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson FinalizableReference.class, this); 127090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson threadStarted = true; 128090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } catch (IllegalAccessException e) { 129090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // Finalizer.startFinalizer() is public. 130090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new AssertionError(e); 131090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } catch (Throwable t) { 132090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson logger.log(Level.INFO, "Failed to start reference finalizer thread." 133090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson + " Reference cleanup will only occur when new references are" 134090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson + " created.", t); 135090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson queue = new ReferenceQueue<Object>(); 136090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 137090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 138090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson this.queue = queue; 139090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson this.threadStarted = threadStarted; 140090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 141090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 142090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 143090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Repeatedly dequeues references from the queue and invokes 144090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * {@link FinalizableReference#finalizeReferent()} on them until the queue 145090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * is empty. This method is a no-op if the background thread was created 146090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * successfully. 147090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 148090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson void cleanUp() { 149090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (threadStarted) { 150090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return; 151090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 152090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 153090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Reference<?> reference; 154090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson while ((reference = queue.poll()) != null) { 155090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /* 156090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * This is for the benefit of phantom references. Weak and soft 157090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * references will have already been cleared by this point. 158090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 159090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson reference.clear(); 160090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson try { 161090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson ((FinalizableReference) reference).finalizeReferent(); 162090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } catch (Throwable t) { 163090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson logger.log(Level.SEVERE, "Error cleaning up after reference.", t); 164090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 165090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 166090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 167090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 168090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 169090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Iterates through the given loaders until it finds one that can load 170090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Finalizer. 171090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 172090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @return Finalizer.class 173090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 174090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private static Class<?> loadFinalizer(FinalizerLoader... loaders) { 175090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (FinalizerLoader loader : loaders) { 176090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Class<?> finalizer = loader.loadFinalizer(); 177090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (finalizer != null) { 178090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return finalizer; 179090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 180090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 181090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 182090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new AssertionError(); 183090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 184090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 185090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 186090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Loads Finalizer.class. 187090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 188090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson interface FinalizerLoader { 189090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 190090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 191090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns Finalizer.class or null if this loader shouldn't or can't load 192090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * it. 193090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 194090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws SecurityException if we don't have the appropriate privileges 195090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 196090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Class<?> loadFinalizer(); 197090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 198090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 199090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 200090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Tries to load Finalizer from the system class loader. If Finalizer is 201090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * in the system class path, we needn't create a separate loader. 202090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 203090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson static class SystemLoader implements FinalizerLoader { 204090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public Class<?> loadFinalizer() { 205090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson ClassLoader systemLoader; 206090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson try { 207090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson systemLoader = ClassLoader.getSystemClassLoader(); 208090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } catch (SecurityException e) { 209090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson logger.info("Not allowed to access system class loader."); 210090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return null; 211090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 212090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (systemLoader != null) { 213090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson try { 214090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return systemLoader.loadClass(FINALIZER_CLASS_NAME); 215090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } catch (ClassNotFoundException e) { 216090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // Ignore. Finalizer is simply in a child class loader. 217090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return null; 218090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 219090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } else { 220090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return null; 221090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 222090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 223090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 224090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 225090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 226090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Try to load Finalizer in its own class loader. If Finalizer's thread 227090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * had a direct reference to our class loader (which could be that of 228090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * a dynamically loaded web application or OSGi bundle), it would prevent 229090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * our class loader from getting garbage collected. 230090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 231090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson static class DecoupledLoader implements FinalizerLoader { 232090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 233090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private static final String LOADING_ERROR = "Could not load Finalizer in" 234090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson + " its own class loader. Loading Finalizer in the current class loader" 235090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson + " instead. As a result, you will not be able to garbage collect this" 236090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson + " class loader. To support reclaiming this class loader, either" 237090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson + " resolve the underlying issue, or move Google Collections to your" 238090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson + " system class path."; 239090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 240090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public Class<?> loadFinalizer() { 241090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson try { 242090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /* 243090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * We use URLClassLoader because it's the only concrete class loader 244090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * implementation in the JDK. If we used our own ClassLoader subclass, 245090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Finalizer would indirectly reference this class loader: 246090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 247090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Finalizer.class -> 248090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * CustomClassLoader -> 249090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * CustomClassLoader.class -> 250090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * This class loader 251090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 252090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * System class loader will (and must) be the parent. 253090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 254090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson ClassLoader finalizerLoader = newLoader(getBaseUrl()); 255090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return finalizerLoader.loadClass(FINALIZER_CLASS_NAME); 256090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } catch (Exception e) { 257090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson logger.log(Level.WARNING, LOADING_ERROR, e); 258090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return null; 259090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 260090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 261090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 262090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 263090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Gets URL for base of path containing Finalizer.class. 264090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 265090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson URL getBaseUrl() throws IOException { 266090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // Find URL pointing to Finalizer.class file. 267090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson String finalizerPath = FINALIZER_CLASS_NAME.replace('.', '/') + ".class"; 268090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson URL finalizerUrl = getClass().getClassLoader().getResource(finalizerPath); 269090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (finalizerUrl == null) { 270090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new FileNotFoundException(finalizerPath); 271090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 272090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 273090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // Find URL pointing to base of class path. 274090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson String urlString = finalizerUrl.toString(); 275090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (!urlString.endsWith(finalizerPath)) { 276090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new IOException("Unsupported path style: " + urlString); 277090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 278090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson urlString = urlString.substring(0, 279090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson urlString.length() - finalizerPath.length()); 280090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new URL(finalizerUrl, urlString); 281090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 282090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 283090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** Creates a class loader with the given base URL as its classpath. */ 284090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson URLClassLoader newLoader(URL base) { 285090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new URLClassLoader(new URL[] { base }); 286090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 287090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 288090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 289090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 290090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Loads Finalizer directly using the current class loader. We won't be 291090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * able to garbage collect this class loader, but at least the world 292090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * doesn't end. 293090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 294090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson static class DirectLoader implements FinalizerLoader { 295090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public Class<?> loadFinalizer() { 296090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson try { 297090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return Class.forName(FINALIZER_CLASS_NAME); 298090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } catch (ClassNotFoundException e) { 299090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new AssertionError(e); 300090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 301090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 302090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 303090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 304090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 305090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Looks up Finalizer.startFinalizer(). 306090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 307090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson static Method getStartFinalizer(Class<?> finalizer) { 308090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson try { 309090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return finalizer.getMethod("startFinalizer", Class.class, Object.class); 310090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } catch (NoSuchMethodException e) { 311090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new AssertionError(e); 312090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 313090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 314090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson} 315