17dd252788645e940eada959bdde927426e2531c9Paul Duffin/* 27dd252788645e940eada959bdde927426e2531c9Paul Duffin * Copyright (C) 2005 The Guava Authors 37dd252788645e940eada959bdde927426e2531c9Paul Duffin * 47dd252788645e940eada959bdde927426e2531c9Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License"); 57dd252788645e940eada959bdde927426e2531c9Paul Duffin * you may not use this file except in compliance with the License. 67dd252788645e940eada959bdde927426e2531c9Paul Duffin * You may obtain a copy of the License at 77dd252788645e940eada959bdde927426e2531c9Paul Duffin * 87dd252788645e940eada959bdde927426e2531c9Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0 97dd252788645e940eada959bdde927426e2531c9Paul Duffin * 107dd252788645e940eada959bdde927426e2531c9Paul Duffin * Unless required by applicable law or agreed to in writing, software 117dd252788645e940eada959bdde927426e2531c9Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS, 127dd252788645e940eada959bdde927426e2531c9Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137dd252788645e940eada959bdde927426e2531c9Paul Duffin * See the License for the specific language governing permissions and 147dd252788645e940eada959bdde927426e2531c9Paul Duffin * limitations under the License. 157dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 167dd252788645e940eada959bdde927426e2531c9Paul Duffin 177dd252788645e940eada959bdde927426e2531c9Paul Duffinpackage com.google.common.base; 187dd252788645e940eada959bdde927426e2531c9Paul Duffin 197dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.testing.GcFinalization; 207dd252788645e940eada959bdde927426e2531c9Paul Duffin 217dd252788645e940eada959bdde927426e2531c9Paul Duffinimport junit.framework.TestCase; 227dd252788645e940eada959bdde927426e2531c9Paul Duffin 237dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.io.Closeable; 247dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.ref.WeakReference; 257dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Constructor; 267dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Field; 277dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.net.URL; 287dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.net.URLClassLoader; 297dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.security.Permission; 307dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.security.Policy; 317dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.security.ProtectionDomain; 327dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.Callable; 337dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.Semaphore; 347dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.TimeUnit; 357dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.atomic.AtomicReference; 367dd252788645e940eada959bdde927426e2531c9Paul Duffin 377dd252788645e940eada959bdde927426e2531c9Paul Duffin/** 387dd252788645e940eada959bdde927426e2531c9Paul Duffin * Tests that the {@code ClassLoader} of {@link FinalizableReferenceQueue} can be unloaded. These 397dd252788645e940eada959bdde927426e2531c9Paul Duffin * tests are separate from {@link FinalizableReferenceQueueTest} so that they can be excluded from 407dd252788645e940eada959bdde927426e2531c9Paul Duffin * coverage runs, as the coverage system interferes with them. 417dd252788645e940eada959bdde927426e2531c9Paul Duffin * 427dd252788645e940eada959bdde927426e2531c9Paul Duffin * @author Eamonn McManus 437dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 447dd252788645e940eada959bdde927426e2531c9Paul Duffinpublic class FinalizableReferenceQueueClassLoaderUnloadingTest extends TestCase { 457dd252788645e940eada959bdde927426e2531c9Paul Duffin 467dd252788645e940eada959bdde927426e2531c9Paul Duffin /* 477dd252788645e940eada959bdde927426e2531c9Paul Duffin * The following tests check that the use of FinalizableReferenceQueue does not prevent the 487dd252788645e940eada959bdde927426e2531c9Paul Duffin * ClassLoader that loaded that class from later being garbage-collected. If anything continues 497dd252788645e940eada959bdde927426e2531c9Paul Duffin * to reference the FinalizableReferenceQueue class then its ClassLoader cannot be 507dd252788645e940eada959bdde927426e2531c9Paul Duffin * garbage-collected, even if there are no more instances of FinalizableReferenceQueue itself. 517dd252788645e940eada959bdde927426e2531c9Paul Duffin * The code in FinalizableReferenceQueue goes to considerable trouble to ensure that there are 527dd252788645e940eada959bdde927426e2531c9Paul Duffin * no such references and the tests here check that that trouble has not been in vain. 537dd252788645e940eada959bdde927426e2531c9Paul Duffin * 547dd252788645e940eada959bdde927426e2531c9Paul Duffin * When we reference FinalizableReferenceQueue in this test, we are referencing a class that is 557dd252788645e940eada959bdde927426e2531c9Paul Duffin * loaded by this test and that will obviously remain loaded for as long as the test is running. 567dd252788645e940eada959bdde927426e2531c9Paul Duffin * So in order to check ClassLoader garbage collection we need to create a new ClassLoader and 577dd252788645e940eada959bdde927426e2531c9Paul Duffin * make it load its own version of FinalizableReferenceQueue. Then we need to interact with that 587dd252788645e940eada959bdde927426e2531c9Paul Duffin * parallel version through reflection in order to exercise the parallel 597dd252788645e940eada959bdde927426e2531c9Paul Duffin * FinalizableReferenceQueue, and then check that the parallel ClassLoader can be 607dd252788645e940eada959bdde927426e2531c9Paul Duffin * garbage-collected after that. 617dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 627dd252788645e940eada959bdde927426e2531c9Paul Duffin 637dd252788645e940eada959bdde927426e2531c9Paul Duffin public static class MyFinalizableWeakReference extends FinalizableWeakReference<Object> { 647dd252788645e940eada959bdde927426e2531c9Paul Duffin public MyFinalizableWeakReference(Object x, FinalizableReferenceQueue queue) { 657dd252788645e940eada959bdde927426e2531c9Paul Duffin super(x, queue); 667dd252788645e940eada959bdde927426e2531c9Paul Duffin } 677dd252788645e940eada959bdde927426e2531c9Paul Duffin 687dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override 697dd252788645e940eada959bdde927426e2531c9Paul Duffin public void finalizeReferent() { 707dd252788645e940eada959bdde927426e2531c9Paul Duffin } 717dd252788645e940eada959bdde927426e2531c9Paul Duffin } 727dd252788645e940eada959bdde927426e2531c9Paul Duffin 737dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class PermissivePolicy extends Policy { 747dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override 757dd252788645e940eada959bdde927426e2531c9Paul Duffin public boolean implies(ProtectionDomain pd, Permission perm) { 767dd252788645e940eada959bdde927426e2531c9Paul Duffin return true; 777dd252788645e940eada959bdde927426e2531c9Paul Duffin } 787dd252788645e940eada959bdde927426e2531c9Paul Duffin } 797dd252788645e940eada959bdde927426e2531c9Paul Duffin 807dd252788645e940eada959bdde927426e2531c9Paul Duffin private WeakReference<ClassLoader> useFrqInSeparateLoader() throws Exception { 817dd252788645e940eada959bdde927426e2531c9Paul Duffin final URLClassLoader myLoader = (URLClassLoader) getClass().getClassLoader(); 827dd252788645e940eada959bdde927426e2531c9Paul Duffin final URL[] urls = myLoader.getURLs(); 837dd252788645e940eada959bdde927426e2531c9Paul Duffin URLClassLoader sepLoader = new URLClassLoader(urls, myLoader.getParent()); 847dd252788645e940eada959bdde927426e2531c9Paul Duffin // sepLoader is the loader that we will use to load the parallel FinalizableReferenceQueue (FRQ) 857dd252788645e940eada959bdde927426e2531c9Paul Duffin // and friends, and that we will eventually expect to see garbage-collected. The assumption 867dd252788645e940eada959bdde927426e2531c9Paul Duffin // is that the ClassLoader of this test is a URLClassLoader, and that it loads FRQ itself 877dd252788645e940eada959bdde927426e2531c9Paul Duffin // rather than delegating to a parent ClassLoader. If this assumption is violated the test will 887dd252788645e940eada959bdde927426e2531c9Paul Duffin // fail and will need to be rewritten. 897dd252788645e940eada959bdde927426e2531c9Paul Duffin 907dd252788645e940eada959bdde927426e2531c9Paul Duffin Class<?> frqC = FinalizableReferenceQueue.class; 917dd252788645e940eada959bdde927426e2531c9Paul Duffin Class<?> sepFrqC = sepLoader.loadClass(frqC.getName()); 927dd252788645e940eada959bdde927426e2531c9Paul Duffin assertNotSame(frqC, sepFrqC); 937dd252788645e940eada959bdde927426e2531c9Paul Duffin // Check the assumptions above. 947dd252788645e940eada959bdde927426e2531c9Paul Duffin 957dd252788645e940eada959bdde927426e2531c9Paul Duffin // FRQ tries to load the Finalizer class (for the reference-collecting thread) in a few ways. 967dd252788645e940eada959bdde927426e2531c9Paul Duffin // If the class is accessible to the system ClassLoader (ClassLoader.getSystemClassLoader()) 977dd252788645e940eada959bdde927426e2531c9Paul Duffin // then FRQ does not bother to load Finalizer.class through a separate ClassLoader. That happens 987dd252788645e940eada959bdde927426e2531c9Paul Duffin // in our test environment, which foils the purpose of this test, so we disable the logic for 997dd252788645e940eada959bdde927426e2531c9Paul Duffin // our test by setting a static field. We are changing the field in the parallel version of FRQ 1007dd252788645e940eada959bdde927426e2531c9Paul Duffin // and each test creates its own one of those, so there is no test interference here. 1017dd252788645e940eada959bdde927426e2531c9Paul Duffin Class<?> sepFrqSystemLoaderC = 1027dd252788645e940eada959bdde927426e2531c9Paul Duffin sepLoader.loadClass(FinalizableReferenceQueue.SystemLoader.class.getName()); 1037dd252788645e940eada959bdde927426e2531c9Paul Duffin Field disabled = sepFrqSystemLoaderC.getDeclaredField("disabled"); 1047dd252788645e940eada959bdde927426e2531c9Paul Duffin disabled.setAccessible(true); 1057dd252788645e940eada959bdde927426e2531c9Paul Duffin disabled.set(null, true); 1067dd252788645e940eada959bdde927426e2531c9Paul Duffin 1077dd252788645e940eada959bdde927426e2531c9Paul Duffin // Now make a parallel FRQ and an associated FinalizableWeakReference to an object, in order to 1087dd252788645e940eada959bdde927426e2531c9Paul Duffin // exercise some classes from the parallel ClassLoader. 1097dd252788645e940eada959bdde927426e2531c9Paul Duffin AtomicReference<Object> sepFrqA = new AtomicReference<Object>(sepFrqC.newInstance()); 1100888a09821a98ac0680fad765217302858e70fa4Paul Duffin Class<?> sepFwrC = sepLoader.loadClass(MyFinalizableWeakReference.class.getName()); 1110888a09821a98ac0680fad765217302858e70fa4Paul Duffin Constructor<?> sepFwrCons = sepFwrC.getConstructor(Object.class, sepFrqC); 1127dd252788645e940eada959bdde927426e2531c9Paul Duffin // The object that we will wrap in FinalizableWeakReference is a Stopwatch. 1137dd252788645e940eada959bdde927426e2531c9Paul Duffin Class<?> sepStopwatchC = sepLoader.loadClass(Stopwatch.class.getName()); 1147dd252788645e940eada959bdde927426e2531c9Paul Duffin assertSame(sepLoader, sepStopwatchC.getClassLoader()); 1157dd252788645e940eada959bdde927426e2531c9Paul Duffin AtomicReference<Object> sepStopwatchA = 1160888a09821a98ac0680fad765217302858e70fa4Paul Duffin new AtomicReference<Object>(sepStopwatchC.getMethod("createUnstarted").invoke(null)); 1170888a09821a98ac0680fad765217302858e70fa4Paul Duffin AtomicReference<WeakReference<?>> sepStopwatchRef = new AtomicReference<WeakReference<?>>( 1180888a09821a98ac0680fad765217302858e70fa4Paul Duffin (WeakReference<?>) sepFwrCons.newInstance(sepStopwatchA.get(), sepFrqA.get())); 1197dd252788645e940eada959bdde927426e2531c9Paul Duffin assertNotNull(sepStopwatchA.get()); 1207dd252788645e940eada959bdde927426e2531c9Paul Duffin // Clear all references to the Stopwatch and wait for it to be gc'd. 1217dd252788645e940eada959bdde927426e2531c9Paul Duffin sepStopwatchA.set(null); 1227dd252788645e940eada959bdde927426e2531c9Paul Duffin GcFinalization.awaitClear(sepStopwatchRef.get()); 1237dd252788645e940eada959bdde927426e2531c9Paul Duffin // Return a weak reference to the parallel ClassLoader. This is the reference that should 1247dd252788645e940eada959bdde927426e2531c9Paul Duffin // eventually become clear if there are no other references to the ClassLoader. 1257dd252788645e940eada959bdde927426e2531c9Paul Duffin return new WeakReference<ClassLoader>(sepLoader); 1267dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1277dd252788645e940eada959bdde927426e2531c9Paul Duffin 1287dd252788645e940eada959bdde927426e2531c9Paul Duffin private void doTestUnloadable() throws Exception { 1297dd252788645e940eada959bdde927426e2531c9Paul Duffin WeakReference<ClassLoader> loaderRef = useFrqInSeparateLoader(); 1307dd252788645e940eada959bdde927426e2531c9Paul Duffin GcFinalization.awaitClear(loaderRef); 1317dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1327dd252788645e940eada959bdde927426e2531c9Paul Duffin 1337dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testUnloadableWithoutSecurityManager() throws Exception { 1347dd252788645e940eada959bdde927426e2531c9Paul Duffin // Test that the use of a FinalizableReferenceQueue does not subsequently prevent the 1357dd252788645e940eada959bdde927426e2531c9Paul Duffin // loader of that class from being garbage-collected. 1367dd252788645e940eada959bdde927426e2531c9Paul Duffin SecurityManager oldSecurityManager = System.getSecurityManager(); 1377dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 1387dd252788645e940eada959bdde927426e2531c9Paul Duffin System.setSecurityManager(null); 1397dd252788645e940eada959bdde927426e2531c9Paul Duffin doTestUnloadable(); 1407dd252788645e940eada959bdde927426e2531c9Paul Duffin } finally { 1417dd252788645e940eada959bdde927426e2531c9Paul Duffin System.setSecurityManager(oldSecurityManager); 1427dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1437dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1447dd252788645e940eada959bdde927426e2531c9Paul Duffin 1457dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testUnloadableWithSecurityManager() throws Exception { 1467dd252788645e940eada959bdde927426e2531c9Paul Duffin // Test that the use of a FinalizableReferenceQueue does not subsequently prevent the 1477dd252788645e940eada959bdde927426e2531c9Paul Duffin // loader of that class from being garbage-collected even if there is a SecurityManager. 1487dd252788645e940eada959bdde927426e2531c9Paul Duffin // The SecurityManager environment makes such leaks more likely because when you create 1497dd252788645e940eada959bdde927426e2531c9Paul Duffin // a URLClassLoader with a SecurityManager, the creating code's AccessControlContext is 1507dd252788645e940eada959bdde927426e2531c9Paul Duffin // captured, and that references the creating code's ClassLoader. 1517dd252788645e940eada959bdde927426e2531c9Paul Duffin Policy oldPolicy = Policy.getPolicy(); 1527dd252788645e940eada959bdde927426e2531c9Paul Duffin SecurityManager oldSecurityManager = System.getSecurityManager(); 1537dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 1547dd252788645e940eada959bdde927426e2531c9Paul Duffin Policy.setPolicy(new PermissivePolicy()); 1557dd252788645e940eada959bdde927426e2531c9Paul Duffin System.setSecurityManager(new SecurityManager()); 1567dd252788645e940eada959bdde927426e2531c9Paul Duffin doTestUnloadable(); 1577dd252788645e940eada959bdde927426e2531c9Paul Duffin } finally { 1587dd252788645e940eada959bdde927426e2531c9Paul Duffin System.setSecurityManager(oldSecurityManager); 1597dd252788645e940eada959bdde927426e2531c9Paul Duffin Policy.setPolicy(oldPolicy); 1607dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1617dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1627dd252788645e940eada959bdde927426e2531c9Paul Duffin 1637dd252788645e940eada959bdde927426e2531c9Paul Duffin public static class FrqUser implements Callable<WeakReference<Object>> { 1647dd252788645e940eada959bdde927426e2531c9Paul Duffin public static FinalizableReferenceQueue frq = new FinalizableReferenceQueue(); 1657dd252788645e940eada959bdde927426e2531c9Paul Duffin public static final Semaphore finalized = new Semaphore(0); 1667dd252788645e940eada959bdde927426e2531c9Paul Duffin 1677dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override 1687dd252788645e940eada959bdde927426e2531c9Paul Duffin public WeakReference<Object> call() { 1697dd252788645e940eada959bdde927426e2531c9Paul Duffin WeakReference<Object> wr = new FinalizableWeakReference<Object>(new Integer(23), frq) { 1707dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override 1717dd252788645e940eada959bdde927426e2531c9Paul Duffin public void finalizeReferent() { 1727dd252788645e940eada959bdde927426e2531c9Paul Duffin finalized.release(); 1737dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1747dd252788645e940eada959bdde927426e2531c9Paul Duffin }; 1757dd252788645e940eada959bdde927426e2531c9Paul Duffin return wr; 1767dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1777dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1787dd252788645e940eada959bdde927426e2531c9Paul Duffin 1797dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testUnloadableInStaticFieldIfClosed() throws Exception { 1807dd252788645e940eada959bdde927426e2531c9Paul Duffin Policy oldPolicy = Policy.getPolicy(); 1817dd252788645e940eada959bdde927426e2531c9Paul Duffin SecurityManager oldSecurityManager = System.getSecurityManager(); 1827dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 1837dd252788645e940eada959bdde927426e2531c9Paul Duffin Policy.setPolicy(new PermissivePolicy()); 1847dd252788645e940eada959bdde927426e2531c9Paul Duffin System.setSecurityManager(new SecurityManager()); 1857dd252788645e940eada959bdde927426e2531c9Paul Duffin WeakReference<ClassLoader> loaderRef = doTestUnloadableInStaticFieldIfClosed(); 1867dd252788645e940eada959bdde927426e2531c9Paul Duffin GcFinalization.awaitClear(loaderRef); 1877dd252788645e940eada959bdde927426e2531c9Paul Duffin } finally { 1887dd252788645e940eada959bdde927426e2531c9Paul Duffin System.setSecurityManager(oldSecurityManager); 1897dd252788645e940eada959bdde927426e2531c9Paul Duffin Policy.setPolicy(oldPolicy); 1907dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1917dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1927dd252788645e940eada959bdde927426e2531c9Paul Duffin 1937dd252788645e940eada959bdde927426e2531c9Paul Duffin // If you have a FinalizableReferenceQueue that is a static field of one of the classes of your 1947dd252788645e940eada959bdde927426e2531c9Paul Duffin // app (like the FrqUser class above), then the app's ClassLoader will never be gc'd. The reason 1957dd252788645e940eada959bdde927426e2531c9Paul Duffin // is that we attempt to run a thread in a separate ClassLoader that will detect when the FRQ 1967dd252788645e940eada959bdde927426e2531c9Paul Duffin // is no longer referenced, meaning that the app's ClassLoader has been gc'd, and when that 1977dd252788645e940eada959bdde927426e2531c9Paul Duffin // happens. But the thread's supposedly separate ClassLoader actually has a reference to the app's 1987dd252788645e940eada959bdde927426e2531c9Paul Duffin // ClasLoader via its AccessControlContext. It does not seem to be possible to make a 1997dd252788645e940eada959bdde927426e2531c9Paul Duffin // URLClassLoader without capturing this reference, and it probably would not be desirable for 2007dd252788645e940eada959bdde927426e2531c9Paul Duffin // security reasons anyway. Therefore, the FRQ.close() method provides a way to stop the thread 2017dd252788645e940eada959bdde927426e2531c9Paul Duffin // explicitly. This test checks that calling that method does allow an app's ClassLoader to be 2027dd252788645e940eada959bdde927426e2531c9Paul Duffin // gc'd even if there is a still a FinalizableReferenceQueue in a static field. (Setting the field 2037dd252788645e940eada959bdde927426e2531c9Paul Duffin // to null would also work, but only if there are no references to the FRQ anywhere else.) 2047dd252788645e940eada959bdde927426e2531c9Paul Duffin private WeakReference<ClassLoader> doTestUnloadableInStaticFieldIfClosed() throws Exception { 2057dd252788645e940eada959bdde927426e2531c9Paul Duffin final URLClassLoader myLoader = (URLClassLoader) getClass().getClassLoader(); 2067dd252788645e940eada959bdde927426e2531c9Paul Duffin final URL[] urls = myLoader.getURLs(); 2077dd252788645e940eada959bdde927426e2531c9Paul Duffin URLClassLoader sepLoader = new URLClassLoader(urls, myLoader.getParent()); 2087dd252788645e940eada959bdde927426e2531c9Paul Duffin 2097dd252788645e940eada959bdde927426e2531c9Paul Duffin Class<?> frqC = FinalizableReferenceQueue.class; 2107dd252788645e940eada959bdde927426e2531c9Paul Duffin Class<?> sepFrqC = sepLoader.loadClass(frqC.getName()); 2117dd252788645e940eada959bdde927426e2531c9Paul Duffin assertNotSame(frqC, sepFrqC); 2127dd252788645e940eada959bdde927426e2531c9Paul Duffin 2137dd252788645e940eada959bdde927426e2531c9Paul Duffin Class<?> sepFrqSystemLoaderC = 2147dd252788645e940eada959bdde927426e2531c9Paul Duffin sepLoader.loadClass(FinalizableReferenceQueue.SystemLoader.class.getName()); 2157dd252788645e940eada959bdde927426e2531c9Paul Duffin Field disabled = sepFrqSystemLoaderC.getDeclaredField("disabled"); 2167dd252788645e940eada959bdde927426e2531c9Paul Duffin disabled.setAccessible(true); 2177dd252788645e940eada959bdde927426e2531c9Paul Duffin disabled.set(null, true); 2187dd252788645e940eada959bdde927426e2531c9Paul Duffin 2197dd252788645e940eada959bdde927426e2531c9Paul Duffin Class<?> frqUserC = FrqUser.class; 2207dd252788645e940eada959bdde927426e2531c9Paul Duffin Class<?> sepFrqUserC = sepLoader.loadClass(frqUserC.getName()); 2217dd252788645e940eada959bdde927426e2531c9Paul Duffin assertNotSame(frqUserC, sepFrqUserC); 2227dd252788645e940eada959bdde927426e2531c9Paul Duffin assertSame(sepLoader, sepFrqUserC.getClassLoader()); 2237dd252788645e940eada959bdde927426e2531c9Paul Duffin 2240888a09821a98ac0680fad765217302858e70fa4Paul Duffin Callable<?> sepFrqUser = (Callable<?>) sepFrqUserC.newInstance(); 2250888a09821a98ac0680fad765217302858e70fa4Paul Duffin WeakReference<?> finalizableWeakReference = (WeakReference<?>) sepFrqUser.call(); 2267dd252788645e940eada959bdde927426e2531c9Paul Duffin 2277dd252788645e940eada959bdde927426e2531c9Paul Duffin GcFinalization.awaitClear(finalizableWeakReference); 2287dd252788645e940eada959bdde927426e2531c9Paul Duffin 2297dd252788645e940eada959bdde927426e2531c9Paul Duffin Field sepFrqUserFinalizedF = sepFrqUserC.getField("finalized"); 2307dd252788645e940eada959bdde927426e2531c9Paul Duffin Semaphore finalizeCount = (Semaphore) sepFrqUserFinalizedF.get(null); 2317dd252788645e940eada959bdde927426e2531c9Paul Duffin boolean finalized = finalizeCount.tryAcquire(5, TimeUnit.SECONDS); 2327dd252788645e940eada959bdde927426e2531c9Paul Duffin assertTrue(finalized); 2337dd252788645e940eada959bdde927426e2531c9Paul Duffin 2347dd252788645e940eada959bdde927426e2531c9Paul Duffin Field sepFrqUserFrqF = sepFrqUserC.getField("frq"); 2357dd252788645e940eada959bdde927426e2531c9Paul Duffin Closeable frq = (Closeable) sepFrqUserFrqF.get(null); 2367dd252788645e940eada959bdde927426e2531c9Paul Duffin frq.close(); 2377dd252788645e940eada959bdde927426e2531c9Paul Duffin 2387dd252788645e940eada959bdde927426e2531c9Paul Duffin return new WeakReference<ClassLoader>(sepLoader); 2397dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2407dd252788645e940eada959bdde927426e2531c9Paul Duffin} 241