I'm trying to write a Java unit test that tests the effects of a call to a finalizer on an object.
In order to be sure the finalizer gets called I'm using a WeakReference method I saw elsewhere on stackoverflow.
My problem is that in this test the finalize method of TestFinalizer never gets called even though the WeakReference comes up null after just one iteration:
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);
}
}
Your call to
System.gc
is only a suggestion, not an order.There is no explicit guarantee that any finalizers will be called.
In your case finalizer would probably be called when the VM exits.
System.gc()
does not trigger a garbage collection.You may be lucky to see the finalizer being called if you add a(doesn't help, just tested)Thread.sleep(xxx)
to your while loop and just wait some time.Adding a Thread.sleep(3000) in the unit test fixed this issue on my machine:
This is performed right before the
assertEquals
call . As others have stated calling System.gc() is a suggestion and the system can ignore you if it so chooses. As an added, I also made sure nothing was static, not sure if that matters.