< prev index next >

test/jdk/java/lang/ClassLoader/forNameLeak/ClassForNameLeak.java

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. --- 1,7 ---- /* ! * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.
*** 30,46 **** * @build jdk.testlibrary.Utils JarUtils * @build ClassForName ClassForNameLeak * @run main/othervm/policy=test.policy -Djava.security.manager ClassForNameLeak */ import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.net.URL; import java.net.URLClassLoader; - import java.nio.file.FileSystems; - import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; --- 30,46 ---- * @build jdk.testlibrary.Utils JarUtils * @build ClassForName ClassForNameLeak * @run main/othervm/policy=test.policy -Djava.security.manager ClassForNameLeak */ + import java.io.IOException; import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; + import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService;
*** 53,121 **** /* * Create .jar, load ClassForName from .jar using a URLClassLoader */ public class ClassForNameLeak { private static final long TIMEOUT = (long)(5000.0 * Utils.TIMEOUT_FACTOR); - private static final String TESTCLASSES = System.getProperty("test.classes", "."); - private static final String CLASSFILENAME = "ClassForName.class"; private static final int THREADS = 10; private static final ReferenceQueue<ClassLoader> rq = new ReferenceQueue<>(); // Use a new classloader to load the ClassForName class, then run its // Runnable. ! public static PhantomReference<ClassLoader> loadAndRun(Path jarFilePath) ! throws Exception { ! ClassLoader classLoader = new URLClassLoader( ! new URL[]{jarFilePath.toUri().toURL()}) { ! @Override public String toString() { return "LeakedClassLoader"; } ! }; Class<?> loadClass = Class.forName("ClassForName", true, classLoader); ((Runnable) loadClass.newInstance()).run(); ! PhantomReference<ClassLoader> ref = new PhantomReference<>(classLoader, rq); ! System.out.println("returning phantom ref: " + ref + " to " + classLoader); ! return ref; } ! public static void main(final String[] args) throws Exception { ! // Create a temporary .jar file containing ClassForName.class ! Path testClassesDir = Paths.get(TESTCLASSES); ! Path jarFilePath = Files.createTempFile("cfn", ".jar"); ! JarUtils.createJarFile(jarFilePath, testClassesDir, CLASSFILENAME); ! jarFilePath.toFile().deleteOnExit(); ! // Remove the ClassForName.class file that jtreg built, to make sure ! // we're loading from the tmp .jar ! Path classFile = FileSystems.getDefault().getPath(TESTCLASSES, ! CLASSFILENAME); ! Files.delete(classFile); // Make simultaneous calls to the test method, to stress things a bit ExecutorService es = Executors.newFixedThreadPool(THREADS); ! List<Callable<PhantomReference<ClassLoader>>> callables = Stream.generate(() -> { ! Callable<PhantomReference<ClassLoader>> cprcl = () -> { ! return loadAndRun(jarFilePath); ! }; return cprcl; }).limit(THREADS).collect(Collectors.toList()); ! List<Future<PhantomReference<ClassLoader>>> refs = es.invokeAll(callables); // Give the GC a chance to enqueue the PhantomReferences for (int i = 0; i < 10; i++) { System.gc(); } // Make sure all PhantomReferences to the leaked classloader are enqueued ! for (int j = 0; j < THREADS; j++) { Reference rmRef = rq.remove(TIMEOUT); if (rmRef == null) { throw new RuntimeException("ClassLoader was never enqueued!"); } else { System.out.println("Enqueued " + rmRef); } } ! System.out.println("All Classloaders successfully enqued"); } } --- 53,132 ---- /* * Create .jar, load ClassForName from .jar using a URLClassLoader */ public class ClassForNameLeak { private static final long TIMEOUT = (long)(5000.0 * Utils.TIMEOUT_FACTOR); private static final int THREADS = 10; + private static final Path jarFilePath = Paths.get("cfn.jar"); private static final ReferenceQueue<ClassLoader> rq = new ReferenceQueue<>(); + static class TestLoader { + private final PhantomReference<ClassLoader> ref; + TestLoader() { + this.ref = loadAndRun(); + } + // Use a new classloader to load the ClassForName class, then run its // Runnable. ! PhantomReference<ClassLoader> loadAndRun() { ! try { ! ClassLoader classLoader = ! new URLClassLoader("LeakedClassLoader", ! new URL[]{jarFilePath.toUri().toURL()}, ! ClassLoader.getPlatformClassLoader()); Class<?> loadClass = Class.forName("ClassForName", true, classLoader); ((Runnable) loadClass.newInstance()).run(); ! return new PhantomReference<>(classLoader, rq); ! } catch (MalformedURLException|ReflectiveOperationException e) { ! throw new RuntimeException(e); ! } } ! PhantomReference<ClassLoader> getRef() { ! return ref; ! } ! } ! public static void main(String... args) throws Exception { ! // create the JAR file ! setup(); // Make simultaneous calls to the test method, to stress things a bit ExecutorService es = Executors.newFixedThreadPool(THREADS); ! List<Callable<TestLoader>> callables = Stream.generate(() -> { ! Callable<TestLoader> cprcl = TestLoader::new; return cprcl; }).limit(THREADS).collect(Collectors.toList()); ! List<Future<TestLoader>> futures = es.invokeAll(callables); // Give the GC a chance to enqueue the PhantomReferences for (int i = 0; i < 10; i++) { System.gc(); } + // Make sure all PhantomReferences to the leaked classloader are enqueued ! for (int j = 0; j < futures.size(); j++) { Reference rmRef = rq.remove(TIMEOUT); if (rmRef == null) { throw new RuntimeException("ClassLoader was never enqueued!"); } else { System.out.println("Enqueued " + rmRef); } } ! es.shutdown(); ! System.out.println("All ClassLoaders successfully enqueued"); ! } ! ! private static final String CLASSFILENAME = "ClassForName.class"; ! private static void setup() throws IOException { ! String testclasses = System.getProperty("test.classes", "."); ! ! // Create a temporary .jar file containing ClassForName.class ! Path testClassesDir = Paths.get(testclasses); ! JarUtils.createJarFile(jarFilePath, testClassesDir, CLASSFILENAME); } }
< prev index next >