2009-04-20 13 views
19

Pregunta rápida sobre la teoría de GCing. Tengo el siguiente método. Se ejecuta y sale del método. ¿Cómo es que incluso después de que se ejecuta el GC, el temporizador todavía existe y mantiene "TICK" ing? No creo que todavía haya una referencia al temporizador o al cronometraje después de que este método exista, por lo que esperaría que el temporizador se convirtiera en GC y ocasionara una excepción. Por favor, ayúdame a entender este concepto.Java: ¿Por qué no se recoge basura?

Gracias, JBU

private void startTimer() 
    { 
     Timer timer= new Timer(); 
     TimerTask timerTask= new TimerTask() 
     { 

      @Override 
      public void run() 
      { 
       System.out.println("TICK"); 
      } 
     }; 

     timer.scheduleAtFixedRate(timerTask, 
       0, 
       500); 
    } 
+0

¿No sería horrible si lo hizo desaparecer? Haría casi todas las multitareas más difíciles. –

Respuesta

0

¿Cómo sabe la RAN GC? La recolección de basura en general no es algo determinante, y definitivamente no se desencadena por el alcance del método. No es como C++ donde dejas el alcance de una función y los destructores disparan. Pasará a recoger esa memoria si el GC lo desea.

+1

He llamado al GC explícitamente a través del modo de depuración de netbeans. – jbu

33

El objeto Timer en realidad programa las tareas que se ejecutarán en una cadena de fondo, por lo que la cadena de fondo mantiene una referencia al temporizador (y al TimerTask), lo que evita que ambas sean recolectadas.

Esta es la cita apropiada de los documentos:

Después de la última referencia en vivo a un objeto temporizador se va y todos tareas pendientes han completado ejecución, ejecución de tareas hilo del temporizador termina con gracia (y queda sujeto a la recolección de basura ). Sin embargo, esto puede tomar arbitrariamente largo para ocurrir. De forma predeterminada, el subproceso de ejecución de tareas no se ejecuta como un subproceso de daemon, por lo que es capaz de mantener una aplicación de terminando. Si una persona que llama quiere terminar la ejecución de la tarea de un temporizador enhebrar rápidamente, la persona que llama debe llamar al para cancelar el método del temporizador.

Por lo tanto, no se cumple la condición de que "todas las tareas pendientes han completado la ejecución" y el hilo nunca termina, por lo que el temporizador/TimerTask nunca se pasa por GC.

+0

Exactamente. Desde los JavaDocs de Timer: "Correspondientemente a cada objeto del temporizador hay un único hilo de fondo que se usa para ejecutar todas las tareas del temporizador, secuencialmente". –

+0

Sin embargo, si cancelo el temporizador, el temporizador/TimerTask eventualmente será sometido a GC? – ptikobj

2

No se ha recopilado el temporizador porque todavía se está ejecutando: algún otro objeto (como el programador de subprocesos) todavía tiene una referencia, que probablemente se creó dentro de scheduleAtFixedRate().

12

Debido a que un programador tiene un background thread that continues running:

correspondiente a cada objeto Timer es un solo hilo de fondo que es utilizado para ejecutar todas las tareas del temporizador, secuencialmente. Las tareas del temporizador deben completarse rápidamente. Si una tarea de temporizador tarda demasiado tiempo en completarse, "encierra" la ejecución de tareas del temporizador subproceso. Esto puede, a su vez, retrasar la ejecución de las tareas posteriores , que puede "agrupar" y ejecutar en sucesión rápida cuando (y si) la tarea ofensiva finalmente se completa.

Como es una cadena de fondo, continúa hasta que la JVM se cierra o se detiene.

Actualización: un poco más sobre esto. Un "hilo de fondo" es lo mismo que un hilo daemon, nombrado por analogía con un proceso daemon BSD. Si ves las javadocs en Thread, encontrará:

marcas de este hilo, ya sea como un hilo de utilidad o un hilo de usuario. La máquina virtual Java se cierra cuando los únicos hilos que se ejecutan son todos hilos daemon .

Cuando finaliza su principal, todos los subprocesos de usuario se detienen, dejando solo los hilos de daemon. La JVM luego se apaga. Para un buen momento, si es corto, llame al Thread.currentThread().setDaemon(true); desde la página principal.

Actualización: Ack. Tenía ese casi a la derecha. Tienes que hacer que el temporizador sea un daemon en el momento de la construcción. (Cambió esto, o lo que acabo de tener un fallo cerebral?)

De todos modos, aquí está el código ejemplo:

import java.util.*; 

class Chatter extends TimerTask { 
    public void run(){ 
     System.err.println("Timer run."); 
    } 
} 

public class TryThread { 
    public static void main(String[] argv){ 
     // If argument is true, only runs a few times. 
     Timer t = new Timer(false); 
     t.schedule(new Chatter(), 1L, 1L); 
     return ; 
    } 
} 
+2

Solo para enfatizar el punto de Charlie, los hilos en vivo son objetos "raíz" para el recolector de basura. No son basura hasta que mueren y no pueden ser recolectados. Cualquier cosa fuertemente referenciable a partir de un hilo en vivo tampoco es basura. Las clases cargadas funcionan de manera similar. – erickson

+0

Espera, ¿entonces este temporizador puede continuar ejecutándose incluso después de que finalice el programa que lo invocó? –

+0

No, porque cuando el canal public static void principal que se invocó al inicio finaliza, la JVM se apaga en general, lo que significa detener y matar los hilos de fondo. Sin embargo, realmente no recibe GC porque cuando el proceso muere, se libera toda la memoria. –

Cuestiones relacionadas