Почему функция finalize не вызывается в этом модульном тесте? - PullRequest
1 голос
/ 03 марта 2012

Я пытаюсь написать модульный тест Java, который проверяет влияние вызова финализатора на объект.

Чтобы убедиться, что финализатор вызывается, я использую метод WeakReference Iвидел в другом месте на stackoverflow.

Моя проблема заключается в том, что в этом тесте метод финализации TestFinalizer никогда не вызывается, даже если WeakReference возвращается к нулю после одной итерации:

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 ]

4 голосов
/ 03 марта 2012

Ваш звонок на System.gc является всего лишь предложением, а не заказом.

Нет явной гарантии, что будут вызваны какие-либо финализаторы.

В вашем случае вероятно будет вызван финализаторкогда ВМ выходит.

0 голосов
/ 03 марта 2012

Добавление 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 () является предложением, и система может проигнорировать вас, если захочет.Кроме того, я также позаботился о том, чтобы ничего не было статичным, не уверен, что это имеет значение.

0 голосов
/ 03 марта 2012

Вызов метода gc предполагает, что виртуальная машина Java затрачивает усилия на утилизацию неиспользуемых объектов, чтобы сделать доступной память, которую они занимают, для быстрого повторного использования.

System.gc() не запускает сборку мусора.

Вам может повезет увидеть вызов финализатора, если вы добавите Thread.sleep(xxx) в цикл while и просто подождете некоторое время. (не помогаетТолько что проверил)

...