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