Skip to content

Commit e62a7fa

Browse files
8342659: Test vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002.java failed: Class nsk.share.jdi.TestClass1 was not unloaded
Co-authored-by: Chris Plummer <cjplummer@openjdk.org> Reviewed-by: sspitsyn, cjplummer
1 parent 9b9559a commit e62a7fa

File tree

2 files changed

+17
-46
lines changed

2 files changed

+17
-46
lines changed

test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
2828

2929
package nsk.share;
3030

31-
import java.lang.ref.Cleaner;
31+
import java.lang.ref.PhantomReference;
3232
import java.util.*;
3333
import nsk.share.gc.gp.*;
3434
import nsk.share.test.ExecutionController;
@@ -77,19 +77,9 @@ public class ClassUnloader {
7777
public static final String INTERNAL_CLASS_LOADER_NAME = "nsk.share.CustomClassLoader";
7878

7979
/**
80-
* Whole amount of time in milliseconds to wait for class loader to be reclaimed.
80+
* Phantom reference to the class loader.
8181
*/
82-
private static final int WAIT_TIMEOUT = 15000;
83-
84-
/**
85-
* Sleep time in milliseconds for the loop waiting for the class loader to be reclaimed.
86-
*/
87-
private static final int WAIT_DELTA = 1000;
88-
89-
/**
90-
* Has class loader been reclaimed or not.
91-
*/
92-
volatile boolean is_reclaimed = false;
82+
private PhantomReference<Object> customClassLoaderPhantomRef = null;
9383

9484
/**
9585
* Current class loader used for loading classes.
@@ -101,6 +91,14 @@ public class ClassUnloader {
10191
*/
10292
private Vector<Class<?>> classObjects = new Vector<Class<?>>();
10393

94+
/**
95+
* Has class loader been reclaimed or not.
96+
*/
97+
private boolean isClassLoaderReclaimed() {
98+
return customClassLoaderPhantomRef != null
99+
&& customClassLoaderPhantomRef.refersTo(null);
100+
}
101+
104102
/**
105103
* Class object of the first class been loaded with current class loader.
106104
* To get the rest loaded classes use <code>getLoadedClass(int)</code>.
@@ -138,8 +136,7 @@ public CustomClassLoader createClassLoader() {
138136
customClassLoader = new CustomClassLoader();
139137
classObjects.removeAllElements();
140138

141-
// Register a Cleaner to inform us when the class loader has been reclaimed.
142-
Cleaner.create().register(customClassLoader, () -> { is_reclaimed = true; } );
139+
customClassLoaderPhantomRef = new PhantomReference<>(customClassLoader, null);
143140

144141
return customClassLoader;
145142
}
@@ -154,8 +151,7 @@ public void setClassLoader(CustomClassLoader customClassLoader) {
154151
this.customClassLoader = customClassLoader;
155152
classObjects.removeAllElements();
156153

157-
// Register a Cleaner to inform us when the class loader has been reclaimed.
158-
Cleaner.create().register(customClassLoader, () -> { is_reclaimed = true; } );
154+
customClassLoaderPhantomRef = new PhantomReference<>(customClassLoader, null);
159155
}
160156

161157
/**
@@ -244,32 +240,15 @@ public void loadClass(String className, String classDir) throws ClassNotFoundExc
244240
*/
245241
public boolean unloadClass(ExecutionController stresser) {
246242

247-
is_reclaimed = false;
248-
249243
// free references to class and class loader to be able for collecting by GC
250-
long waitTimeout = (customClassLoader == null) ? 0 : WAIT_TIMEOUT;
251244
classObjects.removeAllElements();
252245
customClassLoader = null;
253246

254247
// force class unloading by eating memory pool
255248
eatMemory(stresser);
256249

257-
// give GC chance to run and wait for receiving reclaim notification
258-
long timeToFinish = System.currentTimeMillis() + waitTimeout;
259-
while (!is_reclaimed && System.currentTimeMillis() < timeToFinish) {
260-
if (!stresser.continueExecution()) {
261-
return false;
262-
}
263-
try {
264-
// suspend thread for a while
265-
Thread.sleep(WAIT_DELTA);
266-
} catch (InterruptedException e) {
267-
throw new Failure("Unexpected InterruptedException while class unloading: " + e);
268-
}
269-
}
270-
271250
// force GC to unload marked class loader and its classes
272-
if (is_reclaimed) {
251+
if (isClassLoaderReclaimed()) {
273252
Runtime.getRuntime().gc();
274253
return true;
275254
}

test/hotspot/jtreg/vmTestbase/nsk/share/jpda/AbstractDebuggeeTest.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -149,19 +149,11 @@ public void loadTestClass(String className) {
149149
}
150150
}
151151

152-
public static final int MAX_UNLOAD_ATTEMPS = 5;
153-
154152
public void unloadTestClass(String className, boolean expectedUnloadingResult) {
155153
ClassUnloader classUnloader = loadedClasses.get(className);
156154

157-
int unloadAttemps = 0;
158-
159155
if (classUnloader != null) {
160-
boolean wasUnloaded = false;
161-
162-
while (!wasUnloaded && (unloadAttemps++ < MAX_UNLOAD_ATTEMPS)) {
163-
wasUnloaded = classUnloader.unloadClass();
164-
}
156+
boolean wasUnloaded = classUnloader.unloadClass();
165157

166158
if (wasUnloaded)
167159
loadedClasses.remove(className);

0 commit comments

Comments
 (0)