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
2828
2929package nsk .share ;
3030
31- import java .lang .ref .Cleaner ;
31+ import java .lang .ref .PhantomReference ;
3232import java .util .*;
3333import nsk .share .gc .gp .*;
3434import 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 }
0 commit comments