As Roger mentioned, there is a ForceGC utility in the test library:

    test/lib/jdk/test/lib/util/ForceGC.java

and it's used in a variety of places in the core libs tests. Essentially it sets up a PhantomReference and a ReferenceQueue and runs System.gc() in a loop. I'd strongly recommend using this in preference to allocating a lot of memory in order to provoke OutOfMemoryError. That technique has historically been a cause of test flakiness, and it still is, as you've discovered.

There is also MemoryMXBean.gc(), which does the same thing System.gc() does -- it calls Runtime.getRuntime().gc().

It's true that System.gc() may sometimes be ignored -- for instance if Epsilon GC is enabled -- but for practical purposes, on Hotspot using a standard collector, calling it will eventually cause garbage collection and reference processing.

If at some point the behavior provided by System.gc() is inadequate for our testing, we'll need to plumb a JDK-specific interface that has stronger semantics, and then convert ForceGC to use it so that individual tests won't have to be updated.

There are still some tests that allocate lots of memory in order to provoke OOME and consequently reference processing. They probably need to be run in /othervm mode in order to set custom heap sizes and to avoid interfering with other tests. It would be interesting to see if those could be adjusted to use something ForceGC so that they can share the JVM with other tests and also avoid allocating lots of memory.

s'marks


On 3/3/23 10:02 AM, Aleksei Ivanov wrote:
Hello,

In clientlibs, there's occasionally a need to verify an object isn't leaked. For this purpose, WeakReference or PhantomReference is used.

Then, we need to make the reference object be cleared, so a GC cycle need to be triggered. The common approach is generating OutOfMemoryError, catching it and verifying whether the reference is cleared.

Some tests use a utility method regtesthelpers/Util.generateOOME [1].

For example, these tests follow the above approach:
https://github.com/openjdk/jdk/blob/master/test/jdk/javax/swing/border/TestTitledBorderLeak.java
https://github.com/openjdk/jdk/blob/master/test/jdk/java/awt/List/ListGarbageCollectionTest/AwtListGarbageCollectionTest.java


The AwtListGarbageCollectionTest.java test started to fail pretty often in the end of January 2023.

I followed a piece of advice provided in a JBS comment for JDK-8300727 [2] and replaced generating OOME with a simple call to System.gc() along with adding a loop for re-trying.

The specification for System.gc() [3] mentions that this call can be ignored, which started a discussion in the PR #12594 [4] that System.gc() should not be used, at the very least without generating OOME in addition to invoking System.gc().

At the same time, many tests for Reference objects, such as ReferenceEnqueue.java [5] and PhantomReferentClearing.java [6], rely solely on System.gc.


What would be your recommendation? Are there best practices in core-libs and hotspot for testing for memory leaks that clientlibs should follow?


--
Regards,
Alexey

[1] https://github.com/openjdk/jdk/blob/29ee7c3b70ded8cd124ca5b4a38a2aee7c39068b/test/jdk/javax/swing/regtesthelpers/Util.java#L87
[2] https://bugs.openjdk.org/browse/JDK-8300727
[3] https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/System.html#gc()
[4] https://github.com/openjdk/jdk/pull/12594
[5] https://github.com/openjdk/jdk/blob/f612dcfebea7ffd4390f833646ad45d6f0ebd04f/test/jdk/java/lang/ref/ReferenceEnqueue.java#L54-L60 [6] https://github.com/openjdk/jdk/blob/f612dcfebea7ffd4390f833646ad45d6f0ebd04f/test/jdk/java/lang/ref/PhantomReferentClearing.java#L85-L92

Reply via email to