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