1
1
/*
2
- * Copyright (c) 2016, 2018 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2016, 2023 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
28
28
* from a custom classloader.
29
29
* @library /test/lib
30
30
* @build jdk.test.lib.Utils
31
+ * jdk.test.lib.util.ForceGC
31
32
* jdk.test.lib.util.JarUtils
32
33
* @build ClassForName ClassForNameLeak
33
34
* @run main/othervm/policy=test.policy -Djava.security.manager ClassForNameLeak
34
35
*/
35
36
36
37
import java .io .IOException ;
37
- import java .lang .ref .PhantomReference ;
38
- import java .lang .ref .Reference ;
39
- import java .lang .ref .ReferenceQueue ;
38
+ import java .lang .ref .WeakReference ;
40
39
import java .net .MalformedURLException ;
41
40
import java .net .URL ;
42
41
import java .net .URLClassLoader ;
51
50
import java .util .stream .Stream ;
52
51
53
52
import jdk .test .lib .Utils ;
53
+ import jdk .test .lib .util .ForceGC ;
54
54
import jdk .test .lib .util .JarUtils ;
55
55
56
56
/*
@@ -60,35 +60,32 @@ public class ClassForNameLeak {
60
60
private static final long TIMEOUT = (long )(5000.0 * Utils .TIMEOUT_FACTOR );
61
61
private static final int THREADS = 10 ;
62
62
private static final Path jarFilePath = Paths .get ("cfn.jar" );
63
- private static final ReferenceQueue <ClassLoader > rq = new ReferenceQueue <>();
64
63
65
- static class TestLoader {
66
- private final PhantomReference <ClassLoader > ref ;
67
- TestLoader () {
68
- this .ref = loadAndRun ();
69
- }
70
-
71
- // Use a new classloader to load the ClassForName class, then run its
72
- // Runnable.
73
- PhantomReference <ClassLoader > loadAndRun () {
64
+ static class TestLoader extends URLClassLoader {
65
+ static URL [] toURLs () {
74
66
try {
75
- ClassLoader classLoader =
76
- new URLClassLoader ("LeakedClassLoader" ,
77
- new URL []{jarFilePath .toUri ().toURL ()},
78
- ClassLoader .getPlatformClassLoader ());
79
-
80
- Class <?> loadClass = Class .forName ("ClassForName" , true , classLoader );
81
- ((Runnable ) loadClass .newInstance ()).run ();
82
-
83
- return new PhantomReference <>(classLoader , rq );
84
- } catch (MalformedURLException |ReflectiveOperationException e ) {
67
+ return new URL []{jarFilePath .toUri ().toURL ()};
68
+ } catch (MalformedURLException e ) {
85
69
throw new RuntimeException (e );
86
70
}
87
71
}
88
72
89
- PhantomReference <ClassLoader > getRef () {
90
- return ref ;
73
+ TestLoader () {
74
+ super ("LeakedClassLoader" , toURLs (), ClassLoader .getPlatformClassLoader ());
75
+ }
76
+ }
77
+
78
+ // Use a new classloader to load the ClassForName class, then run its
79
+ // Runnable.
80
+ static WeakReference <TestLoader > loadAndRun () {
81
+ TestLoader classLoader = new TestLoader ();
82
+ try {
83
+ Class <?> loadClass = Class .forName ("ClassForName" , true , classLoader );
84
+ ((Runnable ) loadClass .newInstance ()).run ();
85
+ } catch (ReflectiveOperationException ex ) {
86
+ throw new RuntimeException (ex );
91
87
}
88
+ return new WeakReference <>(classLoader );
92
89
}
93
90
94
91
public static void main (String ... args ) throws Exception {
@@ -98,30 +95,19 @@ public static void main(String... args) throws Exception {
98
95
// Make simultaneous calls to the test method, to stress things a bit
99
96
ExecutorService es = Executors .newFixedThreadPool (THREADS );
100
97
101
- List <Callable <TestLoader >> callables =
98
+ List <Callable <WeakReference < TestLoader > >> callables =
102
99
Stream .generate (() -> {
103
- Callable <TestLoader > cprcl = TestLoader :: new ;
100
+ Callable <WeakReference < TestLoader >> cprcl = ClassForNameLeak :: loadAndRun ;
104
101
return cprcl ;
105
102
}).limit (THREADS ).collect (Collectors .toList ());
106
103
107
- List <Future <TestLoader >> futures = es .invokeAll (callables );
108
-
109
- // Give the GC a chance to enqueue the PhantomReferences
110
- for (int i = 0 ; i < 10 ; i ++) {
111
- System .gc ();
112
- }
113
-
114
- // Make sure all PhantomReferences to the leaked classloader are enqueued
115
- for (int j = 0 ; j < futures .size (); j ++) {
116
- Reference rmRef = rq .remove (TIMEOUT );
117
- if (rmRef == null ) {
118
- throw new RuntimeException ("ClassLoader was never enqueued!" );
119
- } else {
120
- System .out .println ("Enqueued " + rmRef );
104
+ for (Future <WeakReference <TestLoader >> future : es .invokeAll (callables )) {
105
+ WeakReference <TestLoader > ref = future .get ();
106
+ if (!ForceGC .wait (() -> ref .refersTo (null ))) {
107
+ throw new RuntimeException (ref .get () + " not unloaded" );
121
108
}
122
109
}
123
110
es .shutdown ();
124
- System .out .println ("All ClassLoaders successfully enqueued" );
125
111
}
126
112
127
113
private static final String CLASSFILENAME = "ClassForName.class" ;
1 commit comments
openjdk-notifier[bot] commentedon Jul 4, 2024
Review
Issues