Почему функция finalize не вызывается в этом модульном тесте?
Я пытаюсь написать модульный тест Java, который проверяет влияние вызова финализатора на объект.
Чтобы быть уверенным, что финализатор вызывается, я использую метод WeakReference, который я видел в другом месте в stackru.
Моя проблема в том, что в этом тесте метод финализации 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 ответа
Добавление 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() является предложением, и система может проигнорировать вас, если захочет. Как добавленный, я также удостоверился, что ничто не было статичным, не уверен, имеет ли это значение.
Ваш звонок в System.gc
это только предложение, а не заказ.
Нет явной гарантии, что будут вызваны финализаторы.
В вашем случае финализатор, вероятно, будет вызван при выходе из виртуальной машины.
Вызов метода gc предполагает, что виртуальная машина Java затрачивает усилия на утилизацию неиспользуемых объектов, чтобы сделать доступной память, которую они занимают, для быстрого повторного использования.
System.gc()
не запускает сборку мусора.
Возможно, вам повезет увидеть вызов финализатора, если вы добавитеThread.sleep(xxx)
к вашему циклу while и просто подождите некоторое время. (не помогает, только что проверил)