Me intrigó el answer a una pregunta similar. Yo creo que es incorrecto Así que creé un código de prueba. Mi pregunta es, ¿este código comprueba/refuta/no concluye la hipótesis de que es útil anular variables miembro en métodos de desmontaje? Lo probé con JUnit4.8.1.¿Es realmente necesario anular objetos en métodos de desmontaje JUnit?
JUnit crea una nueva instancia de la clase de prueba para cada una de las 4 pruebas. Cada instancia contiene un Object obj. Este obj también se inserta como la clave de un WeakHashMap estático. Si y cuando JUnit libera sus referencias a una instancia de prueba, el valor obj asociado se referenciará débilmente y por lo tanto es elegible para gc. La prueba intenta forzar un gc. El tamaño de WeakHashMap me dirá si los objs están escritos o no. Algunas pruebas anularon la variable obj y otras no.
import org . junit . Before ;
import org . junit . After ;
import org . junit . Test ;
import java . util . ArrayList ;
import java . util . WeakHashMap ;
import java . util . concurrent . atomic . AtomicInteger ;
import static org . junit . Assert . * ;
public class Memory
{
static AtomicInteger idx = new AtomicInteger (0) ;
static WeakHashMap < Object , Object > map = new WeakHashMap < Object , Object > () ;
int id ;
Object obj ;
boolean nullify ;
public Memory ()
{
super () ;
}
@ Before
public void before ()
{
id = idx . getAndIncrement () ;
obj = new Object () ;
map . put (obj , new Object ()) ;
System . out . println ("<BEFORE TEST " + id + ">") ;
}
void test (boolean n)
{
nullify = n ;
int before = map . size () ;
gc () ;
int after = map . size () ;
System . out . println ("BEFORE=" + before + "\tAFTER=" + after) ;
}
@ Test
public void test0 ()
{
test (true) ;
}
@ Test
public void test1 ()
{
test (false) ;
}
@ Test
public void test2 ()
{
test (true) ;
}
@ Test
public void test3 ()
{
test (false) ;
}
@ After
public void after ()
{
if (nullify)
{
System . out . println ("Nullifying obj") ;
obj = null ;
}
System . out . println ("<AFTER TEST " + id + ">") ;
}
/**
* Try to force a gc when one is not really needed.
**/
void gc ()
{
ArrayList <Object> waste = new ArrayList <Object> () ;
System . gc () ; // only a suggestion but I'll try to force it
list :
while (true) // try to force a gc
{
try
{
waste . add (new Object ()) ;
}
catch (OutOfMemoryError cause)
{
// gc forced? should have been
waste = null ;
break list ;
}
}
System . gc () ; // only a suggestion but I tried to force it
}
}
Me corrió el código utilizando la interfaz de línea de comandos (utilizando la opción -Xmx128k para aumentar la recolección de basura) y obtuvo el siguiente resultado
.<BEFORE TEST 0>
BEFORE=1 AFTER=1
Nullifying obj
<AFTER TEST 0>
.<BEFORE TEST 1>
BEFORE=2 AFTER=1
<AFTER TEST 1>
.<BEFORE TEST 2>
BEFORE=2 AFTER=1
Nullifying obj
<AFTER TEST 2>
.<BEFORE TEST 3>
BEFORE=2 AFTER=1
<AFTER TEST 3>
El obj Test0 fue anulado y en Prueba1 es gc 'ed. Pero el obj Test1 no fue anulado y se convirtió en Test2. Esto sugiere que anular objetos no es necesario.
Esta es la mejor respuesta. La anulación es necesaria (para evitar pérdidas de memoria) en JUnit 3.x. Si usa JUnit4.x y la anulación predeterminada del corredor no es necesaria. Si usa un corredor personalizado, entonces puede necesitar anularlo. – emory