2015-02-04 11 views
6

Dal Java API doc:Quando il thread in Java viene rimosso dalla memoria?

La Java Virtual Machine continua ad eseguire le discussioni fino seguente verifica:

Tutti i thread che non sono thread demoni sono morti, o restituendo dalla chiamata al eseguire il metodo o lanciando un'eccezione che si propaga oltre il metodo run.

Spero che la mia ipotesi sia corretta che una volta che il thread termina il suo metodo run() diventa idoneo per la garbage collection. Nello stesso contesto io sono solo curioso di sapere:

  1. Se non diventa per la garbage collection dopo il ritorno dal run(), se una impostare il suo riferimento alla null di farlo?
  2. Essere idonei per la garbage collection non significa necessariamente che l'oggetto verrà rimosso dalla memoria. È a esclusiva discrezione di il sistema operativo sottostante/JVM quando viene raccolto. Ma come si può essere sicuri (tramite un programma Java o uno strumento esterno) che l'oggetto sia completamente rimosso dalla memoria ?
  3. Se un thread è morto dopo aver completato il suo metodo run(), perché posso ancora essere in grado di eseguire isAlive() o getState() nello stesso oggetto thread ? Entrambe le chiamate restituiscono rispettivamente false e .

risposta

8

La classe Thread è un proxy per il thread reale che si trova nella memoria nativa.

Spero che la mia ipotesi sia corretta che una volta che il thread termina il suo metodo run() diventa idoneo per la garbage collection.

Esiste un po 'di codice dopo run(), questo codice gestisce le eccezioni non rilevate.

Una volta terminato il thread, la sua memoria nativa e lo stack vengono liberati immediatamente senza bisogno di un GC. Tuttavia, l'oggetto Thread è come qualsiasi altro oggetto e vive finché GC non ha deciso che può essere libero, ad es. non c'è un forte riferimento ad esso.

Analogamente, un FileOutputStream è un proxy per un file nel sistema operativo. Puoi ancora avere un riferimento all'oggetto anche dopo che il file è stato close() o addirittura cancellato.

Se non diventa idoneo per la garbage collection dopo il ritorno da run(), si dovrebbe impostare il suo riferimento su null per farlo?

Raramente è necessario farlo ovunque. In effetti è spesso più semplice non mantenere un riferimento al thread in primo luogo, o utilizzare un ExecutorService per gestire i thread.

Quando ho un oggetto il cui campo Thread spesso devo morire questo oggetto quando il filo muore, così il campo non ha bisogno di essere null ED fuori.

Uso anche il pool di thread integrato utilizzato per Fork/Join. Questo è un modo più leggero per eseguire attività in un thread in background poiché non crea e distrugge i thread così tanto.

ExecutorService fjp = ForkJoinPool.commonPool(); 

Essendo per la garbage collection non significa necessariamente che l'oggetto verrà rimosso dalla memoria. È a discrezione esclusiva del sistema operativo/JVM sottostante quando viene raccolto. Ma come si può essere sicuri (tramite un programma Java o uno strumento esterno) che l'oggetto sia completamente rimosso dalla memoria?

Non si può e generalmente non si dovrebbe provare. Il GC pulirà le risorse quando è necessario.

Se si dice che un thread è morto una volta terminato il suo metodo run(), perché posso essere ancora in grado di eseguire isAlive() o getState() sullo stesso oggetto thread? Entrambe le chiamate restituiscono rispettivamente false e RUNNABLE.

L'oggetto thread è come qualsiasi altro oggetto. Puoi chiamare i metodi su di esso finché tieni un riferimento.

3

Il fatto che il thread abbia terminato l'esecuzione non modifica la validità del riferimento all'oggetto. Mentre si detiene tale riferimento, l'oggetto Thread non può essere sottoposto a Garbage Collection.

Ciò significa che mentre si tiene un riferimento al Thread è possibile chiamare cose come isAlive. Quando rilasci tutti i riferimenti, il Thread può essere raccolto.

Se si desidera avere un riferimento a un oggetto senza impedire che l'oggetto venga sottoposto a garbage collection, è necessario utilizzare uno WeakReference. Quando si utilizza tale riferimento, è necessario verificare se esiste ancora riferimento all'oggetto.

0

Quello che credo è che Garbage Collector raccoglie un oggetto quando non ci sono riferimenti di un oggetto nella memoria. In caso di thread, il processo è in esecuzione in modo che gli oggetti thread non vengano raccolti dal garbage collector.

Ogni albero di oggetti deve avere uno o più oggetti radice. Fino a quando l'applicazione può raggiungere quelle radici, tutto l'albero è raggiungibile tramite

javabook.compuware.com/content/memory/how-garbage-collection-works.aspx 
4

Sembra che si sta inciampare sulla errore comune con fili unterstanding in Java: il filo in sé non è un oggetto Java. È una risorsa nativa (thread di esecuzione). Sarà "rimosso dalla memoria" non appena ha terminato di eseguire il suo codice.

L'istanza di Thread, d'altra parte, è solo un semplice oggetto Java con lo stesso ciclo di vita di qualsiasi altro oggetto — eccetto per la regola aggiuntiva che rimane raggiungibile almeno finché il thread nativo sottostante è attivo. Ciò è implicito dal fatto che è sempre possibile chiamare Thread.currentThread().

Quindi, se si conserva un riferimento a un'istanza Thread responsabile di un thread morto, esso non scompare magicamente e tutti i suoi metodi continueranno a funzionare come specificato. Puoi resistere per tutto il tempo che desideri.

Per quanto riguarda la domanda 2, "rimuovere" un oggetto dalla memoria è un termine praticamente privo di significato. Il runtime in sé non ha alcuna idea sugli oggetti raccolti — sono quelli che ha dimenticato circa.

2

Ci sono due cose da considerare sui thread.

  1. Prima e durante l'esecuzione gli oggetti thread stessi sono root GC, ovvero: essi e qualsiasi oggetto fortemente accessibile da essi non possono essere raccolti.
  2. Una volta terminato il thread, "ritorna" a essere un oggetto ordinario. Le stesse regole GC si applicano a loro come a qualsiasi altro oggetto. Per esempio, mentre hai un forte riferimento a loro, non saranno raccolti e sì, puoi chiamare i metodi su di loro senza problemi.

Quindi il mio consiglio è quello di trattare le discussioni "morti" come si farebbe trattare un oggetto di tipo List o Map per esempio. Ciò che si applica a loro si applica ai thread che hanno terminato la corsa.

+0

voto per le radici GC – ciamej

1

Se non diventa idoneo per la garbage collection dopo il ritorno da run(), si dovrebbe impostare il suo riferimento su null per farlo?

E 'sempre meglio esplicitamente oggetti impostato su NULL (se si è certi che non saranno utilizzati in futuro) per rendere il lavoro del GC po' più facile.

class Test { 

protected void finalize() throws Throwable { 
    System.out.println("test finalized"); 
}; 

public static void main(String[] args) { 
    Thread t = new MyThread(); 
    t.start(); 
    Test test = new Test(); 

    try { 
     System.out.println(t.getState()); 
     // t.join(); 
     t = null; 
     test = null; 
     // System.out.println(t.getState()); 

     Thread.sleep(500); // change this to say 2 or 3 sec i.e, until run() completes. The thread object will be finalized 
     System.gc(); 
     System.out.println("gc call done.."); 
     Thread.sleep(1000); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

} 

}

class MyThread extends Thread { 

protected void finalize() throws Throwable { 
    System.out.println("MyThread instance finalized.."); 
}; 

@Override 
public void run() { 
    for (int i = 0; i < 5; i++) { 
     try { 
      Thread.sleep(300); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     System.out.println(i); 

    } 
} 

}

O/P: caso: 1 -> se filo è esecuzione quando chiamata a gc viene effettuata.

RUNNABLE 
0 
gc call done.. 
test finalized 
1 
2 
3 
4 

caso: 2 -> IF thread è terminato l'esecuzione quando chiamata a gc viene effettuata.

 RUNNABLE 
    0 
    gc call done.. 
    test finalized 
    1 
    2 
    3 
    4 
MyThread instance finalized.. 

Essendo per la garbage collection non significa necessariamente che l'oggetto verrà rimosso dalla memoria. È a discrezione esclusiva del sistema operativo/JVM sottostante quando viene raccolto. Ma come si può essere sicuri (tramite un programma Java o uno strumento esterno) che l'oggetto sia completamente rimosso dalla memoria?

In Java, si può dire solo quando l'oggettodiventa irraggiungibile (non GCed, irraggiungibile.). finalize() verrà chiamato quando onjecy diventa non raggiungibile.

Se si dice che un thread è morto una volta terminato il suo metodo run(), perché posso essere ancora in grado di eseguire isAlive() o getState() sullo stesso oggetto thread? Entrambe le chiamate restituiscono rispettivamente false e RUNNABLE. - Il thread potrebbe aver terminato la sua esecuzione. Ma sarà ancora in uno stato. lo stato terminato. Stai chiamando questi metodi su un'istanza di thread. Quindi, contiene ancora alcuni dati di stato.

+0

Ci sono in realtà due stati che si possono distinguere: * finalizzabile * e * finalizzato *. Questo può essere ottenuto da una coda di riferimento fantasma. Tuttavia, anche * finalizzato * non significa "rimosso dalla memoria". –

+0

@MarkoTopolnik - Concordato. * finalizzato * significa semplicemente che l'istanza è ora * non raggiungibile *. – TheLostMind

+0

* finalizable * significa anche "irraggiungibile", ma non definitivamente, a causa della possibile resurrezione. Quindi sì, in effetti solo "finalizzato" significa "definitivamente irraggiungibile". –