为什么在单元测试中不会调用finalize函数?

时间:2012-03-02 20:45:51

标签: java unit-testing finalizer finalize

我正在尝试编写一个Java单元测试,用于测试对对象的终结器调用的影响。

为了确保调用终结器我正在使用WeakReference方法,我在stackoverflow上看到了其他地方。

我的问题是,在这个测试中,即使WeakReference在一次迭代后出现null,也永远不会调用TestFinalizer的finalize方法:

public class FinalizerTest {    
    private static class TestFinalizer {
        public static class Callback {
            public int NumFinalize = 0;

            public void finalized(){
                NumFinalize++;
            }
        }
        private Callback callback;

        public TestFinalizer(Callback callback){
            this.callback = callback;
        }

        @Override
        public void finalize() throws Throwable {
            callback.finalized();
            super.finalize();
        }
    }

    @Test
    public void testForceFinalizer(){
        TestFinalizer.Callback callback = new TestFinalizer.Callback();
        TestFinalizer testFinalizer = new TestFinalizer(callback); 
        // Try to force finalizer to be called
        WeakReference<Object> ref = new WeakReference<Object>(testFinalizer);
        testFinalizer = null;
        int maxTries = 10000, i=0;
        while (ref.get() != null && i<maxTries) {
            ++i;
            System.gc();
        }
        if ( ref.get() != null )
            fail("testFinalizer didn't get cleaned up within maxTries");

        // Last line passes, next fails!
        assertEquals("Should be exactly one call to finalizer", 1, callback.NumFinalize);
    }
}

3 个答案:

答案 0 :(得分:4)

您对System.gc的来电只是一个建议,而非订单。

没有明确保证会调用任何终结器。

在你的情况下,当VM退出时,可能会调用终结器。

答案 1 :(得分:0)

  

调用gc方法表明Java虚拟机花费了大量精力来回收未使用的对象,以使其当前占用的内存可用于快速重用。

System.gc()不会触发垃圾回收。

如果你在while循环中添加Thread.sleep(xxx)并等待一段时间,你可能很幸运地看到调用终结器。(不是帮助,刚刚测试过)

答案 2 :(得分:0)

在单元测试中添加Thread.sleep(3000)修复了我的问题:

 @Test
    public void testForceFinalizer() throws InterruptedException
    {
    FinalizerTest.TestFinalizer f = new FinalizerTest.TestFinalizer(null);
    FinalizerTest.TestFinalizer.Callback callback =  f.new Callback();
    TestFinalizer testFinalizer = new TestFinalizer(callback); // Try to
                                   // force
                                   // finalizer
                                   // to be
                                   // called
    WeakReference<Object> ref = new WeakReference<Object>(testFinalizer);
    testFinalizer = null;
    int maxTries = 10000, i = 0;
    while (ref.get() != null && i < maxTries)
    {
        ++i;
        System.gc();
    }
    if (ref.get() != null)
        fail("testFinalizer didn't get cleaned up within maxTries"); // Last
                                     // line
                                     // passes,
                                     // next
                                     // fails!
    System.out.println("Value: " + callback.NumFinalize);
    Thread.sleep(3000);
    assertEquals("Should be exactly one call to finalizer", 1,
        callback.NumFinalize);

    System.out.println("Value after: " + callback.NumFinalize);

    }

这是在assertEquals电话之前执行的。正如其他人所说,调用System.gc()是一个建议,如果它选择,系统可以忽略你。作为补充,我还确保没有任何东西是静态的,不确定是否重要。