2012-04-30 15 views
17

Duplicar posibles:
Java Thread Garbage collected or notJava hilos y basura colector

Considérese la clase siguiente:

class Foo implements Runnable { 

    public Foo() { 
     Thread th = new Thread (this); 
     th.start(); 
    } 

    public run() { 
    ... // long task 
    } 

} 

Si creamos varios casos de Foo haciendo

new Foo(); 
new Foo(); 
new Foo(); 
new Foo(); 

(tenga en cuenta que no mantenemos un puntero a ellos).

  1. Podría aquellos casos ser eliminado por el recolector de basura antes la rosca en run() extremos? (En otras palabras: ¿hay alguna referencia a las Foo objetos?)

  2. Y, en el otro lado, Will aquellos casos ser removidos por el GC después de que el hilo en `run()' extremos, o son estamos desperdiciando memoria ("pérdida de memoria")?

  3. Si 1. o 2. son un problema, ¿cuál es la forma correcta de hacerlo?

Gracias

+0

De hecho, puedes probar esto muy fácilmente. –

+0

@Quaternion, sí, tal vez, pero la redacción de esa otra pregunta es realmente "ofuscada" y difícil de entender, ¿eh? – cibercitizen1

+1

Esto no es un duplicado. La pregunta vinculada no aborda el aspecto de "¿Será basura recogida en absoluto después de completar" (estaba a punto de preguntar esto específicamente). Solo pregunta/responde el aspecto de "no se GC'ed mientras se ejecuta". Esta pregunta aquí es en mi opinión mejor. – bluenote10

Respuesta

16
  1. Cualquier objeto que se hace referencia por un hilo activo no pueden ser asignados DE.
  2. Sí, las instancias serán eliminadas por el GC después de que finalice el subproceso en `run() '.
  3. Sin problema.
+0

Por favor, dame dónde obtienes esta conclusión. – Chao

2
  1. El objeto Foo es referenciado por el hilo. El subproceso se referencia durante su ejecución todo el tiempo. Por lo tanto, no será basura recolectada.
  2. Sin pérdidas de memoria. El hilo terminará y será objeto de recolección de basura y Foo en este proceso también.
  3. Debería funcionar bien.
10
  1. podría ser eliminado aquellos casos por el recolector de basura antes de que el hilo de rosca en run() termina? (En otras palabras: se hace referencia alguna a los objetos Foo?)

No. Mientras que el constructor está ejecutando GC no recogerá el objeto. De lo contrario, incluso el más simple:

Customer c = new Customer(); 

podría fallar mientras el constructor de Customer se está ejecutando. Por otro lado, cuando inicia un nuevo hilo, el objeto de hilo se convierte en un nuevo raíz de GC, por lo que todo lo mencionado por ese objeto no está sujeto a la recolección de elementos no utilizados.

  1. Y, de otra parte, serán aquellos casos ser removidos por el GC después de la rosca en extremos Run '`(), o estamos perdiendo la memoria ('pérdida de memoria')?

Una vez que el hilo está hecho, ya no es una raíz de la GC. Si ningún otro código apunta a ese objeto de la hebra, será basura recolectada.

  1. Si cualquiera puntos 1 o 2 son un problema, ¿cuál es la forma correcta de hacerlo?

Tu código es correcto. Sin embargo:

  • iniciar un nuevo hilo en un constructor es una idea pobre desde el punto de vista

  • mantener una referencia a todas hilo conductor de pruebas de unidad podría ser beneficioso si, por ejemplo, quieres interrumpir estos hilos más tarde.

+0

@MarkoTopolnik: ¡oh, sí! OP está pasando 'this' al constructor' Thread' que resulta ser una instancia de 'Foo'. Sin embargo, esto es correcto: si 'Foo' tiene algún estado, todas las variables de estado sobrevivirán a GC porque están referenciadas por' Foo' - y 'Foo' es referenciado por el propio subproceso. –

+4

El inicio de un nuevo hilo en un constructor es una mala idea desde el punto de vista de la seguridad del hilo también. En este caso simple, es probable que exista un problema, pero si subclasificó la clase e inicializó algunos campos finales en el constructor de la subclase, podría terminar con que no se inicialicen antes de acceder. –

7

Comenzar un nuevo hilo sin especificar un grupo de hilos se add it to the default group:

Si el grupo es nula y no hay un controlador de seguridad, el grupo se determina por el método de getThreadGroup el gerente de seguridad. Si el grupo es nulo y no hay un administrador de seguridad, o el método getThreadGroup del administrador de seguridad devuelve null, el grupo se configura para que sea el mismo ThreadGroup que el hilo que está creando el nuevo hilo.

El grupo mantendrá una referencia al hilo mientras esté vivo, por lo que no puede ser GC'd durante ese tiempo.

Cuando termina un hilo (= cuando devuelve run() por cualquier razón), el hilo se elimina del grupo de hilos. Esto ocurre en el método privado exit() que se llama desde código nativo. Este es el momento en el que se pierde la última referencia al hilo y se convierte en elegible para GC.

Tenga en cuenta que el código indica que ThreadGroup puede ser null, pero ese no es el caso. Los diversos controles nulos son solo para evitar los NPE en el raro caso de que algo salga mal. En Thread.init(), obtendría NPE si Java no pudiera determinar un grupo de hilos.

0

Suponiendo que está creando los objetos en el método de ejecución, los objetos saldrán del alcance cuando el método de ejecución finalice y luego estará disponible para la recolección de elementos no utilizados. Ejecutar es solo otro método. Usar subprocesos o no no cambia el comportamiento de recolección de basura aquí de ninguna manera. Todo lo que necesita preocuparse es cuando los objetos salen del alcance, que generalmente está vinculado al alcance del bloque (bloque de método, while loop, if block, etc.).

Por lo tanto, ya que no está guardando ninguna referencia al objeto para comenzar, puede extraer la lógica que crea el objeto en su propio método de corta duración. De esta forma, el objeto que se crea no necesita mantenerse fuera del alcance de ese método.

+0

los objetos Foo no se crean en el método run, sino, por ejemplo, en main. – cibercitizen1

+0

simplemente otro bloque de código, no cambia nada –