Java中的自动内存泄漏检测

Dav*_*vid 15 java testing junit unit-testing memory-leaks

我正在考虑Java程序的自动内存泄漏检测.基本算法是创建包含以下逻辑的JUnit:

Call System.gc() several times
Determine initial heap memory consumption using either Runtime class or JMX
Loop 
    Do something that exercises program under test
End loop

Call System.gc() several times
Determine final heap memory consumption
Compare initial and final memory numbers
Run Code Online (Sandbox Code Playgroud)

该循环用于查看内存是否以小增量爬升.

有必要区分内存使用的预期和意外增加.

这不是一个单元测试.但是JUnit框架使用起来很方便.

你认为这种方法有效吗?您是否认为这种方法可以成功识别内存泄漏?你做过这样的事吗?

And*_*ong 18

我为内存泄漏开发了一个简单的单元测试框架,这对我来说是可靠的.基本思想是创建一个对象的弱引用,该对象应该被垃圾收集,执行测试,执行完整的GC,然后验证弱引用是否已被清除.

这是一个使用我的框架的相当典型的回归测试:

public void testDS00032554() throws Exception {
  Project testProject = getTestProject();
  MemoryLeakVerifier verifier = new MemoryLeakVerifier(new RuntimeTestAction(getTestClassMap()));
  testProject.close();
  verifier.assertGarbageCollected("RuntimeTestAction should be garbage collected when project closed");
}
Run Code Online (Sandbox Code Playgroud)

这里有一些注意事项:

  1. 至关重要的是,您希望收集的对象不应存储在单元测试中的变量中,因为它将在测试结束时保留.
  2. 这是一种有用的回归测试技术,其中报告了泄漏并且您知道应该删除哪个对象.
  3. 这种方法的一个问题是,它是很难确定为什么测试失败.此时您将需要一个内存分析器(我偏爱YourKit).然而,对于IMO而言,进行回归测试仍然是有用的,以便将来不会意外地重新引入泄漏.
  4. 我遇到了一些线程问题,并没有立即清除所有引用,因此该方法现在尝试在失败前多次执行GC(如本文所述: Java技巧130:你知道你的数据大小吗?)

这是完整的帮助程序类,以防您想要尝试它:

/**
 * A simple utility class that can verify that an object has been successfully garbage collected.
 */
public class MemoryLeakVerifier {
private static final int MAX_GC_ITERATIONS = 50;
private static final int GC_SLEEP_TIME     = 100;

private final WeakReference reference;

public MemoryLeakVerifier(Object object) {
    this.reference = new WeakReference(object);
}

public Object getObject() {
    return reference.get();
}

/**
 * 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 50 milliseconds and then retry up to
 * 10 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(String name) {
    Runtime runtime = Runtime.getRuntime();
    for (int i = 0; i < MAX_GC_ITERATIONS; i++) {
        runtime.runFinalization();
        runtime.gc();
        if (getObject() == null)
            break;

        // Pause for a while and then go back around the loop to try again...
        try {
            EventQueue.invokeAndWait(Procedure.NoOp); // Wait for the AWT event queue to have completed processing
            Thread.sleep(GC_SLEEP_TIME);
        } catch (InterruptedException e) {
            // Ignore any interrupts and just try again...
        } catch (InvocationTargetException e) {
            // Ignore any interrupts and just try again...
        }
    }
    PanteroTestCase.assertNull(name + ": object should not exist after " + MAX_GC_ITERATIONS + " collections", getObject());
}
Run Code Online (Sandbox Code Playgroud)

}


Tri*_*Man 7

你不能用java做到这一点.垃圾收集器将在确定必要时运行.除此之外,它可以"释放"内存以便可以重用它,但这并不意味着它将释放该块.