2010-11-09 21 views
13

Soy un programador de C++ que ingresa al mundo de Java. Y no puedo deshacerme de la mala sensación de tener que dejar que el recolector de basura de Java haga mi limpieza.Recolección de basura en una variable local

¿Cómo, por ejemplo, se comportará este código en Java?

public void myFunction() { 
    myObject object = new myObject(); 
    object.doSomething(); 
} 

¿Se eliminará el objeto de la variable local cuando sale myFunction()?

¿Debo configurar el objeto como nulo antes de salir, o estará fuera del alcance y será eliminado por el GC? O, en el peor, ¿se filtrará como lo haría en C++?

Respuesta

23

Será basura recogida en algún momento después de que ya no se use. Creo que en las implementaciones actuales de Java realmente persistirá hasta el final del método, mientras que el recolector de basura en .NET es más agresivo. (No sé si hay garantías incluso en Java. Normalmente solo quiere la variable local para persistir más allá de su última lectura posible cuando está depurando.)

Pero no, no lo hace t necesita establecer la variable en nulo, y hacerlo dañaría la legibilidad.

Es poco probable que el objeto recolecte basura inmediatamente después de que el método finalice; depende de cuándo se ejecuta el GC ... y, por supuesto, si algo más se aferra a una referencia al objeto, de todos modos puede no ser elegible para la recolección de basura. No olvide que el valor de la variable es solo una referencia, no el objeto en sí. (Esto puede tardar un tiempo en acostumbrarse a C++).

+0

En implementaciones anteriores, ¿no continuaría realmente hasta el final del método? Eso sería un poco extraño ... –

+2

@Erick: Estaba tratando de evitar la garantía de que las implementaciones * future * mantendrían la variable local como una "raíz". El .NET CLR definitivamente no lo hace, y de hecho un objeto puede ser recogido basura * mientras que un método de instancia todavía está ejecutando "en" it * siempre que el GC sepa que nada hará referencia a ninguno de sus campos. –

+0

@Erick si 'doSomething()' no utiliza ningún otro campo o método del objeto, o el código se puede JIT para que todos los campos se coloquen en registros y todos los métodos estén en línea, entonces el objeto se puede recopilar antes ' doSomething() 'completa, y mucho menos' myFunction() '. El único criterio es si el significado del código cambia. –

1

Saldrá de alcance. En Java, cuando ya nadie apunta a un objeto, será basura recolectada o al menos estará disponible para la recolección de basura. No es necesario configurarlo aquí. En ocasiones, es necesario establecer una referencia de objeto a null si su objeto seguirá vivo en su aplicación, pero una referencia que contenga debe ser recolectada. En este caso, está eligiendo liberar la referencia.

+2

(el -1 corresponde a la parte del alcance. El alcance variable y el ciclo de vida del objeto no están relacionados en absoluto en Java. La segunda parte es menos incorrecta, aunque el criterio es la accesibilidad en lugar de la falta de referencias, si dos objetos 'apuntan' otro, pero ninguno es alcanzable desde ningún otro objeto, entonces serán recogidos basura aunque alguien los señale) –

+0

Gracias interesantes –

2

me encontré con este código:

{ 
    final List myTooBigList = new ArrayList(); 
    ... overfill the list 
} 
somethingRunOutOfMemory(); 

somethingRunOutOfMemory() porque no estaban myTooBigList GCable, a pesar de no alcance nunca más.

Al igual que en C, las variables locales se encuentran en la pila al lado de los marcos. El puntero de pila reserva tanto espacio como se requiere para las variables locales en el alcance. La variable local de un bloque se convierte en GCable cuando se reutiliza la pila. Cuando está fuera del alcance, el puntero se mueve hacia atrás tan pronto como lo requieren las nuevas variables locales.

Ellos son GCable después:

try { } catch : after exit by catch because catch reuses stack 
for { } : after exit loop condition because evaluation reuses stack 
while { }: after exit loop condition because evaluation reuses stack 
{ } followed by any local declaration that reuses stack 

No son GCable después:

try { } finally 
try { } catch : after nothing caught 
for { } : after break 
while { } : after break 
do { } while : after loop condition 
if { } 
{ } not followed by a local declaration 

si quiero un local que se GCable escribo:

{ 
    final List myTooBigList = new ArrayList(); 
    ... overfill the list 
} 
Object fake = null; 
somethingDoesntRunOutOfMemory(); 

Afectación de falsa mueve el puntero de la pila hacia atrás y hace myTooBigList GCable. La sorpresa es que (al menos en el jvm estoy probando) tenemos que reutilizar explícitamente la pila.Se esperaría más que las variables locales se puedan poner en GC tan pronto como se salga del bloque, pero supongo que es un compromiso con el rendimiento. Esto complicaría mucho el bytecode.

NOTA: para comprobar si una variable es GCable, ejecuto GC y luego comparo una WeakReference (mi variable) con nulo.

final WeakReference gctest; 
{ 
    final List myTooBigList = new ArrayList(); 
    gctest = new WeakReference(myTooBigList); 
    ... overfill the list 
} 
Object fake = null; 
System.gc(); 
assert gctest.get() == null;