2010-03-11 10 views
69

Esta pregunta se publicó en algún sitio. No encontré las respuestas correctas allí, así que lo vuelvo a publicar aquí.Java Thread Basura recolectada o no

public class TestThread { 
    public static void main(String[] s) { 
     // anonymous class extends Thread 
     Thread t = new Thread() { 
      public void run() { 
       // infinite loop 
       while (true) { 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
        } 
        // as long as this line printed out, you know it is alive. 
        System.out.println("thread is running..."); 
       } 
      } 
     }; 
     t.start(); // Line A 
     t = null; // Line B 
     // no more references for Thread t 
     // another infinite loop 
     while (true) { 
      try { 
       Thread.sleep(3000); 
      } catch (InterruptedException e) { 
      } 
      System.gc(); 
      System.out.println("Executed System.gc()"); 
     } // The program will run forever until you use ^C to stop it 
    } 
} 

Mi consulta no es sobre stopping a Thread. Permítame rehacer mi pregunta. La línea A (consulte el código anterior) inicia un nuevo subproceso; y la línea B hace que la referencia del hilo sea nula. Entonces, la JVM ahora tiene un objeto de subproceso (que está en estado de ejecución) para el que no existe referencia (como t = nulo en la línea B). Entonces mi pregunta es, ¿por qué este hilo (que ya no tiene referencia en el hilo principal) sigue ejecutándose hasta que se ejecuta el hilo principal? Según entiendo, el objeto thread debería haber sido recogido basura después de la línea B. Intenté ejecutar este código durante 5 minutos y más, solicitando a Java Runtime que ejecute GC, pero el hilo simplemente no se detiene.

Espero que el código y la pregunta estén claros esta vez.

Respuesta

102

Un subproceso en ejecución se considera una llamada raíz de recolección de basura y es una de esas cosas que impide que las cosas se recolecten. Cuando el recolector de basura determina si su objeto es 'reachable' o no, siempre lo hace usando el conjunto de raíces del recolector de basura como puntos de referencia.

Considere esto, ¿por qué su hilo principal no se recoge basura, nadie está haciendo referencia a eso tampoco.

+10

Esta respuesta, tal como está actualmente, plantea la pregunta si los hilos pueden ser sometidos a GC (después de que terminen). Dado que esta pregunta está marcada como un duplicado de [este] (http://stackoverflow.com/questions/10380327/java-threads-and-garbage-collector), se debe mencionar que los hilos ya no estarán marcados como " raíces de recolección de basura "después de que terminan, y por lo tanto, se vuelven alcanzables para GC. – bluenote10

+0

@ bluenote10 correcto, de ahí la frase "hilo de ejecución". – falstro

+10

La última oración es penetrante: "¿por qué tu hilo principal no es basura?". – Determinant

15

La JVM tiene una referencia a todos los subprocesos en ejecución.

Ningún hilo (o las cosas a las que hace referencia) se recogerá mientras se está ejecutando.

8

El subproceso no se recolectó como basura porque hay referencias a los subprocesos que no se pueden ver. Por ejemplo, hay referencias en el sistema de tiempo de ejecución.

Cuando se crea el subproceso, se agrega al grupo de subprocesos actual. Puede obtener una lista de subprocesos en el grupo de subprocesos actual, de modo que esa es otra forma de obtener una referencia.

18

Como se explicó, los hilos en ejecución son, por definición, inmune a GC. El GC comienza su trabajo escaneando "raíces", que se consideran siempre alcanzables; Las raíces incluyen variables globales ("campos estáticos" en Java-talk) y las pilas de todos los hilos en ejecución (se puede imaginar que la pila de un hilo en ejecución hace referencia a la instancia correspondiente Thread).

Sin embargo, puede hacer que un hilo sea un hilo "daemon" (vea Thread.setDaemon(boolean)). Un subproceso de daemon no se recolecta más que un subproceso que no sea de daemon, pero la JVM se cierra cuando todos los subprocesos en ejecución son daemon. Una forma de imaginarlo es que cada subproceso, cuando termina, comprueba si quedan algunos subprocesos que no son de demonio; si no, el hilo de terminación fuerza una llamada System.exit(), que sale de la JVM (eliminando los hilos del daemon en ejecución). Esto no es un problema relacionado con GC; de alguna manera, los hilos se asignan manualmente. Sin embargo, así es como la JVM puede tolerar subprocesos semi-rogue. Esto se suele utilizar para instancias Timer.

Cuestiones relacionadas