8287596: Reorg jdk.test.lib.util.ForceGC

Reviewed-by: rriggs
This commit is contained in:
Xue-Lei Andrew Fan 2022-07-06 14:23:44 +00:00
parent cc2b792704
commit 82a8bd7e92
10 changed files with 54 additions and 79 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -30,8 +30,8 @@ import java.io.ObjectStreamField;
import java.io.Serializable;
import java.util.Arrays;
import org.testng.annotations.Test;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertFalse;
import jdk.test.lib.util.ForceGC;
@ -54,15 +54,14 @@ public class TestOSCClassLoaderLeak {
objectStreamClass_MemoryLeakExample.toString();
WeakReference<Object> myOwnClassLoaderWeakReference = new WeakReference<>(myOwnClassLoader);
assertNotNull(myOwnClassLoaderWeakReference.get());
assertFalse(myOwnClassLoaderWeakReference.refersTo(null));
objectStreamClass_MemoryLeakExample = null;
myOwnClassLoader = null;
loadClass = null;
con = null;
assertNotNull(myOwnClassLoaderWeakReference.get());
assertFalse(myOwnClassLoaderWeakReference.refersTo(null));
ForceGC gc = new ForceGC();
assertTrue(gc.await(() -> myOwnClassLoaderWeakReference.get() == null));
assertTrue(ForceGC.wait(() -> myOwnClassLoaderWeakReference.refersTo(null)));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, BELLSOFT. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -152,8 +152,7 @@ public class LoadLibraryUnload {
clazz = null;
threads = null;
exceptions.clear();
ForceGC gc = new ForceGC();
if (!gc.await(() -> wClass.refersTo(null))) {
if (!ForceGC.wait(() -> wClass.refersTo(null))) {
throw new RuntimeException("Class1 hasn't been GC'ed");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2022, 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
@ -66,9 +66,8 @@ public class NativeLibraryTest {
// Unload the class loader and native library, and give the Cleaner
// thread a chance to unload the native library.
// unloadedCount is incremented when the native library is unloaded.
ForceGC gc = new ForceGC();
final int finalCount = count;
if (!gc.await(() -> finalCount == unloadedCount)) {
if (!ForceGC.wait(() -> finalCount == unloadedCount)) {
throw new RuntimeException("Expected unloaded=" + count +
" but got=" + unloadedCount);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, 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
@ -214,18 +214,15 @@ public class UnloadingTest {
}
void unload() {
// Force garbage collection to trigger unloading of class loader and native library
ForceGC gc = new ForceGC();
assertTrue(gc.await(() -> weakRef.get() == null));
if (weakRef.get() != null) {
// Force garbage collection to trigger unloading of class loader
// and native library.
if (!ForceGC.wait(() -> weakRef.refersTo(null))) {
throw new RuntimeException("loader " + " not unloaded!");
}
}
boolean tryUnload() {
ForceGC gc = new ForceGC();
return gc.await(() -> weakRef.get() == null);
return ForceGC.wait(() -> weakRef.refersTo(null));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, 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
@ -107,9 +107,7 @@ public class ReflectionCallerCacheTest {
WeakReference<?> weakLoader = loadAndRunClass(classname);
// Force garbage collection to trigger unloading of class loader
new ForceGC().await(() -> weakLoader.get() == null);
if (weakLoader.get() != null) {
if (!ForceGC.wait(() -> weakLoader.refersTo(null))) {
throw new RuntimeException("Class " + classname + " not unloaded!");
}
}

View File

@ -49,8 +49,7 @@ public final class CheckCleanerBound {
// Check if the object has been collected. The collection will not
// happen if the cleaner implementation in PasswordCallback is bound
// to the PasswordCallback object.
ForceGC gc = new ForceGC();
if (!gc.await(() -> weakRef.get() == null)) {
if (!ForceGC.wait(() -> weakRef.refersTo(null))) {
throw new RuntimeException(
"PasswordCallback object is not released");
}

View File

@ -54,8 +54,7 @@ public final class GssContextCleanup {
context = null;
// Check if the object has been collected.
ForceGC gc = new ForceGC();
if (!gc.await(() -> weakRef.get() == null)) {
if (!ForceGC.wait(() -> weakRef.refersTo(null))) {
throw new RuntimeException("GSSContext object is not released");
}
}

View File

@ -55,8 +55,7 @@ public final class GssNameCleanup {
name = null;
// Check if the object has been collected.
ForceGC gc = new ForceGC();
if (!gc.await(() -> weakRef.get() == null)) {
if (!ForceGC.wait(() -> weakRef.refersTo(null))) {
throw new RuntimeException("GSSName object is not released");
}
} catch (GSSException gsse) {

View File

@ -89,10 +89,8 @@ public class MultipleLogins {
Security.removeProvider(providers[i].getName());
providers[i] = null;
ForceGC gc = new ForceGC();
int finalI = i;
gc.await(() -> weakRef[finalI].get() == null);
if (!weakRef[i].refersTo(null)) {
if (!ForceGC.wait(() -> weakRef[finalI].refersTo(null))) {
throw new RuntimeException("Expected SunPKCS11 Provider to be GC'ed..");
}
}

View File

@ -23,68 +23,56 @@
package jdk.test.lib.util;
import java.lang.ref.Cleaner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.function.BooleanSupplier;
/**
* Utility class to invoke System.gc()
*/
public class ForceGC {
private final static Cleaner cleaner = Cleaner.create();
private final CountDownLatch cleanerInvoked;
private Object o;
private int gcCount = 0;
public ForceGC() {
this.o = new Object();
this.cleanerInvoked = new CountDownLatch(1);
cleaner.register(o, cleanerInvoked::countDown);
}
private void doit(int iter) {
try {
for (int i = 0; i < 10; i++) {
System.gc();
gcCount++;
if (cleanerInvoked.await(100L, TimeUnit.MILLISECONDS)) {
return;
}
}
} catch (InterruptedException unexpected) {
throw new AssertionError("unexpected InterruptedException");
}
}
// The jtreg testing timeout factor.
private static final double TIMEOUT_FACTOR = Double.valueOf(
System.getProperty("test.timeout.factor", "1.0"));
/**
* Causes the current thread to wait until the {@code BooleanSupplier} returns true,
* unless the thread is interrupted or a predefined waiting time elapses.
* Causes the current thread to wait until the {@code booleanSupplier}
* returns true, or a specific waiting time elapses. The waiting time
* is 1 second scaled with the jtreg testing timeout factor.
*
* @param s boolean supplier
* @return true if the {@code BooleanSupplier} returns true and false if
* the predefined waiting time elapsed before the count reaches zero.
* @throws InterruptedException if the current thread is interrupted while waiting
* @param booleanSupplier boolean supplier
* @return true if the {@code booleanSupplier} returns true, or false
* if did not complete after the specific waiting time.
*/
public boolean await(BooleanSupplier s) {
o = null; // Keep reference to Object until now, to ensure the Cleaner
// doesn't count down the latch before await() is called.
for (int i = 0; i < 10; i++) {
if (s.getAsBoolean()) {
System.out.println("ForceGC condition met after System.gc() " + gcCount + " times");
public static boolean wait(BooleanSupplier booleanSupplier) {
ReferenceQueue<Object> queue = new ReferenceQueue<>();
Object obj = new Object();
PhantomReference<Object> ref = new PhantomReference<>(obj, queue);
obj = null;
Reference.reachabilityFence(obj);
Reference.reachabilityFence(ref);
int retries = (int)(Math.round(1000L * TIMEOUT_FACTOR) / 200);
for (; retries >= 0; retries--) {
if (booleanSupplier.getAsBoolean()) {
return true;
}
doit(i);
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new AssertionError("unexpected interrupted sleep", e);
// The remove() will always block for the specified milliseconds
// if the reference has already been removed from the queue.
// But it is fine. For most cases, the 1st GC is sufficient
// to trigger and complete the cleanup.
queue.remove(200L);
} catch (InterruptedException ie) {
// ignore, the loop will try again
}
}
System.out.println("ForceGC condition not met after System.gc() " + gcCount + " times");
return false;
return booleanSupplier.getAsBoolean();
}
}