2
* Copyright (C) 2011 The Guava Authors
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
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
17
package com.google.common.testing;
19
import static java.util.concurrent.TimeUnit.SECONDS;
21
import com.google.common.annotations.GwtIncompatible;
22
import com.google.common.annotations.J2ktIncompatible;
23
import com.google.errorprone.annotations.DoNotMock;
24
import com.google.j2objc.annotations.J2ObjCIncompatible;
25
import java.lang.ref.WeakReference;
26
import java.util.Locale;
27
import java.util.concurrent.CancellationException;
28
import java.util.concurrent.CountDownLatch;
29
import java.util.concurrent.ExecutionException;
30
import java.util.concurrent.Future;
31
import java.util.concurrent.TimeoutException;
34
* Testing utilities relating to garbage collection finalization.
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:
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
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
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
55
* <p>Here's an example that tests a {@code finalize} method:
58
* final CountDownLatch latch = new CountDownLatch(1);
59
* Object x = new MyClass() {
61
* protected void finalize() { latch.countDown(); ... }
63
* x = null; // Hint to the JIT that x is stack-unreachable
64
* GcFinalization.await(latch);
67
* <p>Here's an example that uses a user-defined finalization predicate:
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();
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:
83
* // Helper function keeps victim stack-unreachable.
84
* private WeakReference<Foo> fooWeakRef() {
86
* WeakReference<Foo> weakRef = new WeakReference<>(x);
88
* x = null; // Hint to the JIT that x is stack-unreachable
91
* public void testFooLeak() {
92
* GcFinalization.awaitClear(fooWeakRef());
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.
99
* <p>This class only provides testing utilities. It is not designed for direct use in production or
102
* @author mike nonemacher
103
* @author Martin Buchholz
108
@J2ObjCIncompatible // gc
109
@ElementTypesAreNonnullByDefault
110
public final class GcFinalization {
111
private GcFinalization() {}
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.
117
private static long timeoutSeconds() {
118
// This class can make no hard guarantees. The methods in this class are inherently flaky, but
119
// we try hard to make them robust in practice. We could additionally try to add in a system
120
// load timeout multiplier. Or we could try to use a CPU time bound instead of wall clock time
121
// bound. But these ideas are harder to implement. We do not try to detect or handle a
122
// user-specified -XX:+DisableExplicitGC.
124
// TODO(user): Consider using
125
// java/lang/management/OperatingSystemMXBean.html#getSystemLoadAverage()
127
// TODO(user): Consider scaling by number of mutator threads,
128
// e.g. using Thread#activeCount()
129
return Math.max(10L, Runtime.getRuntime().totalMemory() / (32L * 1024L * 1024L));
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.
136
* @throws RuntimeException if timed out or interrupted while waiting
138
@SuppressWarnings("removal") // b/260137033
139
public static void awaitDone(Future<?> future) {
140
if (future.isDone()) {
143
long timeoutSeconds = timeoutSeconds();
144
long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);
146
System.runFinalization();
147
if (future.isDone()) {
152
future.get(1L, SECONDS);
154
} catch (CancellationException | ExecutionException ok) {
156
} catch (InterruptedException ie) {
157
throw new RuntimeException("Unexpected interrupt while waiting for future", ie);
158
} catch (TimeoutException tryHarder) {
161
} while (System.nanoTime() - deadline < 0);
162
throw formatRuntimeException("Future not done within %d second timeout", timeoutSeconds);
166
* Waits until the given predicate returns true, invoking the garbage collector as necessary to
167
* try to ensure that this will happen.
169
* @throws RuntimeException if timed out or interrupted while waiting
171
@SuppressWarnings("removal") // b/260137033
172
public static void awaitDone(FinalizationPredicate predicate) {
173
if (predicate.isDone()) {
176
long timeoutSeconds = timeoutSeconds();
177
long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);
179
System.runFinalization();
180
if (predicate.isDone()) {
183
CountDownLatch done = new CountDownLatch(1);
184
createUnreachableLatchFinalizer(done);
186
if (predicate.isDone()) {
189
} while (System.nanoTime() - deadline < 0);
190
throw formatRuntimeException(
191
"Predicate did not become true within %d second timeout", timeoutSeconds);
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.
198
* @throws RuntimeException if timed out or interrupted while waiting
200
@SuppressWarnings("removal") // b/260137033
201
public static void await(CountDownLatch latch) {
202
if (latch.getCount() == 0) {
205
long timeoutSeconds = timeoutSeconds();
206
long deadline = System.nanoTime() + SECONDS.toNanos(timeoutSeconds);
208
System.runFinalization();
209
if (latch.getCount() == 0) {
214
if (latch.await(1L, SECONDS)) {
217
} catch (InterruptedException ie) {
218
throw new RuntimeException("Unexpected interrupt while waiting for latch", ie);
220
} while (System.nanoTime() - deadline < 0);
221
throw formatRuntimeException(
222
"Latch failed to count down within %d second timeout", timeoutSeconds);
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.
229
private static void createUnreachableLatchFinalizer(CountDownLatch latch) {
232
@SuppressWarnings("removal") // b/260137033
234
protected void finalize() {
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()}:
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
251
@DoNotMock("Implement with a lambda")
252
public interface FinalizationPredicate {
257
* Waits until the given weak reference is cleared, invoking the garbage collector as necessary to
258
* try to ensure that this will happen.
260
* <p>This is a convenience method, equivalent to:
263
* awaitDone(new FinalizationPredicate() {
264
* public boolean isDone() {
265
* return ref.get() == null;
270
* @throws RuntimeException if timed out or interrupted while waiting
272
public static void awaitClear(WeakReference<?> ref) {
274
new FinalizationPredicate() {
276
public boolean isDone() {
277
return ref.get() == null;
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.
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.
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
298
* <p>This method does not create any memory pressure as would be required to cause soft
299
* references to be processed.
301
* @throws RuntimeException if timed out or interrupted while waiting
304
@SuppressWarnings("removal") // b/260137033
305
public static void awaitFullGc() {
306
CountDownLatch finalizerRan = new CountDownLatch(1);
307
WeakReference<Object> ref =
311
protected void finalize() {
312
finalizerRan.countDown();
319
// Hope to catch some stragglers queued up behind our finalizable object
320
System.runFinalization();
323
private static RuntimeException formatRuntimeException(String format, Object... args) {
324
return new RuntimeException(String.format(Locale.ROOT, format, args));