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;
En implementaciones anteriores, ¿no continuaría realmente hasta el final del método? Eso sería un poco extraño ... –
@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. –
@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. –