Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 24 additions & 32 deletions src/main/java/org/jvnet/hudson/test/MemoryAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ public static void assertGC(WeakReference<?> reference) {

/**
* Forces GC by causing an OOM and then verifies the given {@link WeakReference} has been garbage collected.
* <p>Beware that failures messages can be misleading and you may need to use heap dumps to diagnose issues.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* <p>Beware that failures messages can be misleading and you may need to use heap dumps to diagnose issues.
* <p>Beware that failure messages can be misleading, and you may need to use heap dumps to diagnose issues.

* @param reference object used to verify garbage collection.
* @param allowSoft if true, pass even if {@link SoftReference}s apparently needed to be cleared by forcing an {@link OutOfMemoryError};
* if false, fail in such a case (though the failure will be slow)
Expand Down Expand Up @@ -192,29 +193,18 @@ public static void assertGC(WeakReference<?> reference, boolean allowSoft) {
Object obj = reference.get();
if (obj != null) {
softErr = "Apparent soft references to " + obj + ": "
+ fromRoots(Set.of(obj), null, null, new Filter() {
final Field referent;

{
try {
referent = Reference.class.getDeclaredField("referent");
} catch (NoSuchFieldException x) {
throw new AssertionError(x);
}
}

@Override
public boolean accept(Object obj, Object referredFrom, Field reference) {
return !referent.equals(reference) || !(referredFrom instanceof WeakReference);
}
})
+ fromRoots(Set.of(obj), null, null, new SkipWeakReferencesFilter())
+ "; apparent weak references: "
+ fromRoots(
Set.of(obj), null, null, ScannerUtils.skipObjectsFilter(Set.of(reference), true));
System.err.println(softErr);
}
}
}
if (softErr != null) {
// Sometimes soft references can be cleared prior to an OutOfMemoryError occurring.
fail(softErr);
}
objects = null;
System.gc();
Object obj = reference.get();
Expand All @@ -228,22 +218,7 @@ public boolean accept(Object obj, Object referredFrom, Field reference) {
fail(rootRefs.toString());
} else {
System.err.println("Did not find any strong references to " + obj + ", looking for soft references…");
rootRefs = fromRoots(Set.of(obj), null, null, new Filter() {
final Field referent;

{
try {
referent = Reference.class.getDeclaredField("referent");
} catch (NoSuchFieldException x) {
throw new AssertionError(x);
}
}

@Override
public boolean accept(Object obj, Object referredFrom, Field reference) {
return !referent.equals(reference) || !(referredFrom instanceof WeakReference);
}
});
rootRefs = fromRoots(Set.of(obj), null, null, new SkipWeakReferencesFilter());
if (!rootRefs.isEmpty()) {
fail(rootRefs.toString());
} else {
Expand Down Expand Up @@ -343,4 +318,21 @@ public void visitObject(ObjectMap map, Object object) {
}
}
}

private static class SkipWeakReferencesFilter implements Filter {
static final Field referent;

static {
try {
referent = Reference.class.getDeclaredField("referent");
} catch (NoSuchFieldException x) {
throw new AssertionError(x);
}
}

@Override
public boolean accept(Object obj, Object referredFrom, Field reference) {
return !referent.equals(reference) || !(referredFrom instanceof WeakReference);
}
}
}