|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- /* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ==================================================================== */
-
- package org.apache.poi.util;
-
- import static org.junit.jupiter.api.Assertions.assertNull;
-
- import java.lang.ref.WeakReference;
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * A simple utility class that can verify that objects have been successfully garbage collected.
- *
- * Usage is something like
- *
- * private final MemoryLeakVerifier verifier = new MemoryLeakVerifier();
-
- {@literal}After
- void tearDown() {
- verifier.assertGarbageCollected();
- }
-
- {@literal}Test
- void someTest() {
- ...
- verifier.addObject(object);
- }
-
- *
- * This will verify at the end of the test if the object is actually removed by the
- * garbage collector or if it lingers in memory for some reason.
- */
- public class MemoryLeakVerifier {
- private static final int MAX_GC_ITERATIONS = 50;
- private static final int GC_SLEEP_TIME = 100;
-
- private final List<WeakReference<Object>> references = new ArrayList<>();
-
- public MemoryLeakVerifier() {
- }
-
- public void addObject(Object object) {
- references.add(new WeakReference<>(object));
- }
-
- /**
- * Attempts to perform a full garbage collection so that all weak references will be removed. Usually only
- * a single GC is required, but there have been situations where some unused memory is not cleared up on the
- * first pass. This method performs a full garbage collection and then validates that the weak reference
- * now has been cleared. If it hasn't then the thread will sleep for 100 milliseconds and then retry up to
- * 50 more times. If after this the object still has not been collected then the assertion will fail.
- *
- * Based upon the method described in: http://www.javaworld.com/javaworld/javatips/jw-javatip130.html
- */
- public void assertGarbageCollected() {
- assertGarbageCollected(MAX_GC_ITERATIONS);
- }
-
- /**
- * Used only for testing the class itself where we would like to fail faster than 5 seconds
- * @param maxIterations The number of times a GC will be invoked until a possible memory leak is reported
- */
- void assertGarbageCollected(int maxIterations) {
- try {
- for(WeakReference<Object> ref : references) {
- assertGarbageCollected(ref, maxIterations);
- }
- } catch (InterruptedException e) {
- // just ensure that we quickly return when the thread is interrupted
- }
- }
-
- private static void assertGarbageCollected(WeakReference<Object> ref, int maxIterations) throws InterruptedException {
- Runtime runtime = Runtime.getRuntime();
- for (int i = 0; i < maxIterations; i++) {
- runtime.runFinalization();
- runtime.gc();
- if (ref.get() == null)
- break;
-
- // Pause for a while and then go back around the loop to try again...
- //EventQueue.invokeAndWait(Procedure.NoOp); // Wait for the AWT event queue to have completed processing
- Thread.sleep(GC_SLEEP_TIME);
- }
-
- assertNull(ref.get(), "Object should not exist after " + MAX_GC_ITERATIONS + " collections, but still had: " + ref.get());
- }
- }
|