1

オブジェクトに対するファイナライザーの呼び出しの影響をテストするJava単体テストを作成しようとしています。

ファイナライザーが確実に呼び出されるようにするために、stackoverflowの他の場所で見たWeakReferenceメソッドを使用しています。

私の問題は、このテストでは、WeakReferenceが1回の反復でヌルになったとしても、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);
    }
}
4

3 に答える 3

4

へのあなたの呼び出しSystem.gcは単なる提案であり、注文ではありません。

ファイナライザーが呼び出されるという明示的な保証はありません。

あなたの場合、VMが終了するときにファイナライザーが呼び出される可能性があります。

于 2012-03-02T20:51:55.983 に答える
0

gcメソッドを呼び出すことは、Java仮想マシンが、現在占有しているメモリを迅速に再利用できるようにするために、未使用のオブジェクトのリサイクルに労力を費やすことを示唆しています。

System.gc()ガベージコレクションはトリガーされません。

whileループにを追加してしばらく待つと、ファイナライザーが呼び出されるのを見ることができますThread.sleep(xxx)(役に立たない、テストしたばかり)

于 2012-03-02T20:55:14.580 に答える
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() の呼び出しは提案であり、システムが選択した場合、システムはあなたを無視できます。追加として、静的なものがないことも確認しましたが、それが重要かどうかはわかりません。

于 2012-03-02T21:35:23.120 に答える