blob: a1c56fa6abe69d8064c1b07b48d6f8439e471190 [file] [log] [blame]
bae86bc2992009-02-04 14:06:18 +03001/*
ohairbf91ea12011-04-06 22:06:11 -07002 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
bae86bc2992009-02-04 14:06:18 +03003 * 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
ohair2283b9d2010-05-25 15:58:33 -070019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
bae86bc2992009-02-04 14:06:18 +030022 */
23
24/**
25 * @test
26 * @bug 6799583
27 *
28 * @summary Test verifes that LogManager shutdown hook does not cause
29 * an application classloader leaks.
30 *
31 * @run main/othervm ClassLoaderLeakTest
32 */
33
34import java.io.File;
35import java.lang.ref.WeakReference;
36import java.lang.reflect.Constructor;
37import java.lang.reflect.Method;
38import java.net.MalformedURLException;
39import java.net.URL;
40import java.net.URLClassLoader;
41import java.util.concurrent.CountDownLatch;
42import java.util.logging.Logger;
43import java.util.logging.Logger;
44
45public class ClassLoaderLeakTest {
46
47 private static CountDownLatch doneSignal;
48 private static CountDownLatch launchSignal;
49 private static ThreadGroup appsThreadGroup;
50 private static Throwable launchFailure = null;
51
52 public static void main(String[] args) {
53 appsThreadGroup = new ThreadGroup("MyAppsThreadGroup");
54 doneSignal = new CountDownLatch(1);
55 launchSignal = new CountDownLatch(1);
56
57 Runnable launcher = new Runnable() {
58 public void run() {
59 try {
60 ClassLoader cl =
61 Thread.currentThread().getContextClassLoader();
62 Class appMain = cl.loadClass("AppTest");
63 Method launch =
64 appMain.getDeclaredMethod("launch", doneSignal.getClass());
65
66 Constructor c = appMain.getConstructor();
67
68 Object o = c.newInstance();
69
70 launch.invoke(o, doneSignal);
71
72 } catch (Throwable e) {
73 launchFailure = e;
74 } finally {
75 launchSignal.countDown();
76 }
77 }
78 };
79
80 /* prepare test class loader */
81 URL pwd = null;
82 try {
83
84 pwd = new File(System.getProperty("test.classes",".")).toURL();
85 } catch (MalformedURLException e) {
86 throw new RuntimeException("Test failed.", e);
87 }
88 URL[] urls = new URL[] { pwd };
89
90 MyClassLoader appClassLoader = new MyClassLoader(urls, "test0");
91 WeakReference<MyClassLoader> ref =
smarks257e5f92010-12-20 13:47:04 -080092 new WeakReference<>(appClassLoader);
bae86bc2992009-02-04 14:06:18 +030093
94
95 Thread appThread = new Thread(appsThreadGroup, launcher, "AppThread-0");
96 appThread.setContextClassLoader(appClassLoader);
97
98 appThread.start();
99 appClassLoader = null;
100 launcher = null;
101 appThread = null;
102
103 /* wait for laucnh completion */
104 try {
105 launchSignal.await();
106 } catch (InterruptedException e) {
107 }
108
109 /* check if launch failed */
110 if (launchFailure != null) {
111 throw new RuntimeException("Test failed.", launchFailure);
112 }
113
114 /* wait for test app excution completion */
115 try {
116 doneSignal.await();
117 } catch (InterruptedException e) {
118 }
119
120 /* give a chence to GC */
121 waitAndGC(5);
122
123 if (ref.get() != null) {
124 throw new RuntimeException("Test failed: classloader is still alive");
125 }
126
127 System.out.println("Test passed.");
128 }
129
130 private static class MyClassLoader extends URLClassLoader {
131
132 private static boolean verbose =
133 Boolean.getBoolean("verboseClassLoading");
134 private String uniqClassName;
135
136 public MyClassLoader(URL[] urls, String uniq) {
137 super(urls);
138
139 uniqClassName = uniq;
140 }
141
142 public Class loadClass(String name) throws ClassNotFoundException {
143 if (verbose) {
144 System.out.printf("%s: load class %s\n", uniqClassName, name);
145 }
146 if (uniqClassName.equals(name)) {
147 return Object.class;
148 }
149 return super.loadClass(name);
150 }
151
152 public String toString() {
153 return "MyClassLoader(" + uniqClassName + ")";
154 }
155 }
156
157 private static void waitAndGC(int sec) {
158 int cnt = sec;
159 System.out.print("Wait ");
160 while (cnt-- > 0) {
161 try {
162 Thread.sleep(1000);
163 } catch (InterruptedException e) {
164 }
165 // do GC every 3 seconds
166 if (cnt % 3 == 2) {
167 System.gc();
168 System.out.print("+");
169 } else {
170 System.out.print(".");
171 }
172 //checkErrors();
173 }
174 System.out.println("");
175 }
176}
177
178
179class AppTest {
180 public AppTest() {
181
182 }
183
184 public void launch(CountDownLatch done) {
185 Logger log = Logger.getLogger("app_test_logger");
186 log.fine("Test app is launched");
187
188 done.countDown();
189 }
190}