Java Thread Garbage Collection raccolto o meno


85

Questa domanda è stata pubblicata su qualche sito. Non ho trovato le risposte giuste lì, quindi lo pubblicherò di nuovo qui.

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
    }
}

La mia domanda non riguarda l'arresto di un thread. Lasciami riformulare la mia domanda. La riga A (vedi codice sopra) inizia un nuovo thread; e la riga B rendono nullo il riferimento al thread. Quindi, la JVM ora ha un oggetto Thread (che è in stato di esecuzione) a cui non esiste alcun riferimento (come t = null nella riga B). Quindi la mia domanda è: perché questo thread (che non ha più riferimenti nel thread principale) continua a funzionare fino a quando il thread principale non è in esecuzione. Per quanto ne so, l'oggetto thread dovrebbe essere stato raccolto in modo indesiderato dopo la riga B. Ho provato a eseguire questo codice per 5 minuti e più, richiedendo a Java Runtime di eseguire GC, ma il thread non si ferma.

Spero che sia il codice che la domanda siano chiari questa volta.

Risposte:


123

Un thread in esecuzione è considerato una cosiddetta radice di garbage collection ed è una di quelle cose che impedisce a cose di essere garbage collection. Quando il garbage collector determina se il tuo oggetto è " raggiungibile " o meno, lo fa sempre utilizzando l'insieme delle radici del garbage collector come punti di riferimento.

Considera questo, perché il tuo thread principale non viene raccolto nella spazzatura, nessuno fa riferimento a quello.


16
Questa risposta, così come è attualmente, solleva la questione se i thread possono essere sottoposti a GC (dopo che sono terminati). Poiché questa domanda è contrassegnata come un duplicato di questa , è opportuno menzionare che i thread non verranno più contrassegnati come "radici di Garbage Collection" dopo essere terminati e pertanto diventano raggiungibili per GC.
bluenote10

13
L'ultima frase è penetrante: "perché il tuo filo conduttore non è spazzatura ...".
Determinante

quindi come follow-up, un thread eliminato (uno che è stato unito) non sarà più considerato una radice? Sono quasi certo che la risposta sia sì, ma vedo cose strane sulla mia applicazione sotto il profiler e mi chiedo ...
Groostav

1
Più risposte leggo, più mi confondo, ma sì, perché il thread principale non viene raccolto dalla spazzatura è qualcosa su cui riflettere. Ma tornando alla domanda principale, se i thread secondari creano alcuni oggetti non verrebbero GCed poiché il thread padre è ancora in esecuzione e contiene i riferimenti dei thread secondari anche se sono stati `` esauriti '' (!! ??)
Rahul Kumar

@Groostav Un thread che è stato unito non è in esecuzione, quindi non è una radice di garbage collection. Ma quando il thread padre ha chiamato child.join(), aveva un riferimento a child. Se quel riferimento (e qualsiasi altro) non viene scartato, il thread figlio non può essere GCed.
Blaisorblade

23

Come è stato spiegato, i thread in esecuzione sono, per definizione, immuni a GC. Il GC inizia il suo lavoro scansionando le "radici", che si ritengono sempre raggiungibili; le radici includono variabili globali ("campi statici" in Java-talk) e gli stack di tutti i thread in esecuzione (si può immaginare che lo stack di un thread in esecuzione faccia riferimento Threadall'istanza corrispondente ).

Tuttavia, puoi trasformare un thread in un thread "demone" (vedi Thread.setDaemon(boolean)). Un thread daemon non è più raccolto in modo indesiderato di un thread non daemon, ma la JVM esce quando tutti i thread in esecuzione sono daemon. Un modo per immaginarlo è che ogni thread, quando termina, controlla se rimangono dei thread in esecuzione non daemon; in caso contrario, il thread di terminazione forza una System.exit()chiamata, che esce dalla JVM (eliminando i thread del daemon in esecuzione). Questo non è un problema relativo a GC; in un certo senso, i thread vengono allocati manualmente. Tuttavia, questo è il modo in cui la JVM può tollerare thread semi-canaglia. Questo è in genere utilizzato per le Timeristanze.


19

La JVM ha un riferimento a tutti i thread in esecuzione.

Nessun thread (o le cose a cui fa riferimento) verrà sottoposto a garbage collection mentre è ancora in esecuzione.


13

Il thread non viene sottoposto a Garbage Collection perché sono presenti riferimenti ai thread che non è possibile visualizzare. Ad esempio, ci sono riferimenti nel sistema runtime.

Quando il thread viene creato, viene aggiunto al gruppo di thread corrente. È possibile ottenere un elenco di thread nel gruppo di thread corrente, quindi questo è un altro modo per ottenere un riferimento ad esso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.