Java
1/*
2* Copyright (C) 2011 The Guava Authors
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17package com.google.common.testing;18
19import static java.util.concurrent.TimeUnit.SECONDS;20
21import com.google.common.annotations.GwtIncompatible;22import com.google.common.annotations.J2ktIncompatible;23import com.google.errorprone.annotations.DoNotMock;24import com.google.j2objc.annotations.J2ObjCIncompatible;25import java.lang.ref.WeakReference;26import java.util.Locale;27import java.util.concurrent.CancellationException;28import java.util.concurrent.CountDownLatch;29import java.util.concurrent.ExecutionException;30import java.util.concurrent.Future;31import java.util.concurrent.TimeoutException;32
33/**
34* Testing utilities relating to garbage collection finalization.
35*
36* <p>Use this class to test code triggered by <em>finalization</em>, that is, one of the following
37* actions taken by the java garbage collection system:
38*
39* <ul>
40* <li>invoking the {@code finalize} methods of unreachable objects
41* <li>clearing weak references to unreachable referents
42* <li>enqueuing weak references to unreachable referents in their reference queue
43* </ul>
44*
45* <p>This class uses (possibly repeated) invocations of {@link java.lang.System#gc()} to cause
46* finalization to happen. However, a call to {@code System.gc()} is specified to be no more than a
47* hint, so this technique may fail at the whim of the JDK implementation, for example if a user
48* specified the JVM flag {@code -XX:+DisableExplicitGC}. But in practice, it works very well for
49* ordinary tests.
50*
51* <p>Failure of the expected event to occur within an implementation-defined "reasonable" time
52* period or an interrupt while waiting for the expected event will result in a {@link
53* RuntimeException}.
54*
55* <p>Here's an example that tests a {@code finalize} method:
56*
57* <pre>{@code
58* final CountDownLatch latch = new CountDownLatch(1);
59* Object x = new MyClass() {
60* ...
61* protected void finalize() { latch.countDown(); ... }
62* };
63* x = null; // Hint to the JIT that x is stack-unreachable
64* GcFinalization.await(latch);
65* }</pre>
66*
67* <p>Here's an example that uses a user-defined finalization predicate:
68*
69* <pre>{@code
70* final WeakHashMap<Object, Object> map = new WeakHashMap<>();
71* map.put(new Object(), Boolean.TRUE);
72* GcFinalization.awaitDone(new FinalizationPredicate() {
73* public boolean isDone() {
74* return map.isEmpty();
75* }
76* });
77* }</pre>
78*
79* <p>Even if your non-test code does not use finalization, you can use this class to test for
80* leaks, by ensuring that objects are no longer strongly referenced:
81*
82* <pre>{@code
83* // Helper function keeps victim stack-unreachable.
84* private WeakReference<Foo> fooWeakRef() {
85* Foo x = ....;
86* WeakReference<Foo> weakRef = new WeakReference<>(x);
87* // ... use x ...
88* x = null; // Hint to the JIT that x is stack-unreachable
89* return weakRef;
90* }
91* public void testFooLeak() {
92* GcFinalization.awaitClear(fooWeakRef());
93* }
94* }</pre>
95*
96* <p>This class cannot currently be used to test soft references, since this class does not try to
97* create the memory pressure required to cause soft references to be cleared.
98*
99* <p>This class only provides testing utilities. It is not designed for direct use in production or
100* for benchmarking.
101*
102* @author mike nonemacher
103* @author Martin Buchholz
104* @since 11.0
105*/
106@GwtIncompatible
107@J2ktIncompatible
108@J2ObjCIncompatible // gc109@ElementTypesAreNonnullByDefault
110public final class GcFinalization {111private GcFinalization() {}112
113/**114* 10 seconds ought to be long enough for any object to be GC'ed and finalized. Unless we have a
115* gigantic heap, in which case we scale by heap size.
116*/
117private static long timeoutSeconds() {118// This class can make no hard guarantees. The methods in this class are inherently flaky, but119// we try hard to make them robust in practice. We could additionally try to add in a system120// load timeout multiplier. Or we could try to use a CPU time bound instead of wall clock time121// bound. But these ideas are harder to implement. We do not try to detect or handle a122// user-specified -XX:+DisableExplicitGC.123//124// TODO(user): Consider using125// java/lang/management/OperatingSystemMXBean.html#getSystemLoadAverage()126//127// TODO(user): Consider scaling by number of mutator threads,128// e.g. using Thread#activeCount()129return Math.max(10L, Runtime.getRuntime().totalMemory() / (32L * 1024L * 1024L));130}131
132/**133* Waits until the given future {@linkplain Future#isDone is done}, invoking the garbage collector
134* as necessary to try to ensure that this will happen.
135*
136* @throws RuntimeException if timed out or interrupted while waiting
137*/
138@SuppressWarnings("removal") // b/260137033139public static void awaitDone(Future<?> future) {140if (future.isDone()) {141return;142}143long timeoutSeconds = timeoutSeconds();144long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);145do {146System.runFinalization();147if (future.isDone()) {148return;149}150System.gc();151try {152future.get(1L, SECONDS);153return;154} catch (CancellationException | ExecutionException ok) {155return;156} catch (InterruptedException ie) {157throw new RuntimeException("Unexpected interrupt while waiting for future", ie);158} catch (TimeoutException tryHarder) {159/* OK */160}161} while (System.nanoTime() - deadline < 0);162throw formatRuntimeException("Future not done within %d second timeout", timeoutSeconds);163}164
165/**166* Waits until the given predicate returns true, invoking the garbage collector as necessary to
167* try to ensure that this will happen.
168*
169* @throws RuntimeException if timed out or interrupted while waiting
170*/
171@SuppressWarnings("removal") // b/260137033172public static void awaitDone(FinalizationPredicate predicate) {173if (predicate.isDone()) {174return;175}176long timeoutSeconds = timeoutSeconds();177long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);178do {179System.runFinalization();180if (predicate.isDone()) {181return;182}183CountDownLatch done = new CountDownLatch(1);184createUnreachableLatchFinalizer(done);185await(done);186if (predicate.isDone()) {187return;188}189} while (System.nanoTime() - deadline < 0);190throw formatRuntimeException(191"Predicate did not become true within %d second timeout", timeoutSeconds);192}193
194/**195* Waits until the given latch has {@linkplain CountDownLatch#countDown counted down} to zero,
196* invoking the garbage collector as necessary to try to ensure that this will happen.
197*
198* @throws RuntimeException if timed out or interrupted while waiting
199*/
200@SuppressWarnings("removal") // b/260137033201public static void await(CountDownLatch latch) {202if (latch.getCount() == 0) {203return;204}205long timeoutSeconds = timeoutSeconds();206long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);207do {208System.runFinalization();209if (latch.getCount() == 0) {210return;211}212System.gc();213try {214if (latch.await(1L, SECONDS)) {215return;216}217} catch (InterruptedException ie) {218throw new RuntimeException("Unexpected interrupt while waiting for latch", ie);219}220} while (System.nanoTime() - deadline < 0);221throw formatRuntimeException(222"Latch failed to count down within %d second timeout", timeoutSeconds);223}224
225/**226* Creates a garbage object that counts down the latch in its finalizer. Sequestered into a
227* separate method to make it somewhat more likely to be unreachable.
228*/
229private static void createUnreachableLatchFinalizer(CountDownLatch latch) {230Object unused =231new Object() {232@SuppressWarnings({"removal", "Finalize"}) // b/260137033233@Override234protected void finalize() {235latch.countDown();236}237};238}239
240/**241* A predicate that is expected to return true subsequent to <em>finalization</em>, that is, one
242* of the following actions taken by the garbage collector when performing a full collection in
243* response to {@link System#gc()}:
244*
245* <ul>
246* <li>invoking the {@code finalize} methods of unreachable objects
247* <li>clearing weak references to unreachable referents
248* <li>enqueuing weak references to unreachable referents in their reference queue
249* </ul>
250*/
251@DoNotMock("Implement with a lambda")252public interface FinalizationPredicate {253boolean isDone();254}255
256/**257* Waits until the given weak reference is cleared, invoking the garbage collector as necessary to
258* try to ensure that this will happen.
259*
260* <p>This is a convenience method, equivalent to:
261*
262* <pre>{@code
263* awaitDone(new FinalizationPredicate() {
264* public boolean isDone() {
265* return ref.get() == null;
266* }
267* });
268* }</pre>
269*
270* @throws RuntimeException if timed out or interrupted while waiting
271*/
272public static void awaitClear(WeakReference<?> ref) {273awaitDone(274new FinalizationPredicate() {275@Override276public boolean isDone() {277return ref.get() == null;278}279});280}281
282/**283* Tries to perform a "full" garbage collection cycle (including processing of weak references and
284* invocation of finalize methods) and waits for it to complete. Ensures that at least one weak
285* reference has been cleared and one {@code finalize} method has been run before this method
286* returns. This method may be useful when testing the garbage collection mechanism itself, or
287* inhibiting a spontaneous GC initiation in subsequent code.
288*
289* <p>In contrast, a plain call to {@link java.lang.System#gc()} does not ensure finalization
290* processing and may run concurrently, for example, if the JVM flag {@code
291* -XX:+ExplicitGCInvokesConcurrent} is used.
292*
293* <p>Whenever possible, it is preferable to test directly for some observable change resulting
294* from GC, as with {@link #awaitClear}. Because there are no guarantees for the order of GC
295* finalization processing, there may still be some unfinished work for the GC to do after this
296* method returns.
297*
298* <p>This method does not create any memory pressure as would be required to cause soft
299* references to be processed.
300*
301* @throws RuntimeException if timed out or interrupted while waiting
302* @since 12.0
303*/
304@SuppressWarnings({"removal", "Finalize"}) // b/260137033305public static void awaitFullGc() {306CountDownLatch finalizerRan = new CountDownLatch(1);307WeakReference<Object> ref =308new WeakReference<>(309new Object() {310@Override311protected void finalize() {312finalizerRan.countDown();313}314});315
316await(finalizerRan);317awaitClear(ref);318
319// Hope to catch some stragglers queued up behind our finalizable object320System.runFinalization();321}322
323private static RuntimeException formatRuntimeException(String format, Object... args) {324return new RuntimeException(String.format(Locale.ROOT, format, args));325}326}
327