我正在尝试编写一个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);
}
}
答案 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()是一个建议,如果它选择,系统可以忽略你。作为补充,我还确保没有任何东西是静态的,不确定是否重要。