Javaスレッドガベージが収集されたかどうか


85

この質問はいくつかのサイトに投稿されました。正しい答えが見つからなかったので、ここにもう一度投稿します。

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

私の質問は、スレッドを停止することではありません。私の質問を言い換えさせてください。行A(上記のコードを参照)は新しいスレッドを開始します。行Bは、スレッド参照をnullにします。そのため、JVMには、参照が存在しないスレッドオブジェクト(実行状態)があります(行Bのt = nullとして)。だから私の質問は、なぜこのスレッド(メインスレッドにもう参照がない)がメインスレッドが実行されるまで実行され続けるのかということです。私の理解では、スレッドオブジェクトは行Bの後にガベージコレクションされているはずです。このコードを5分以上実行して、JavaランタイムにGCを実行するように要求しましたが、スレッドが停止しません。

今回はコードと質問の両方が明確であることを願っています。

回答:


123

実行中のスレッドは、いわゆるガベージコレクションルートと見なされ、ガベージコレクションが行われないようにするものの1つです。ガベージコレクターがオブジェクトが「到達可能」であるかどうかを判断するときは、常にガベージコレクターのルートのセットを参照ポイントとして使用して判断します。

これを考慮してください。メインスレッドがガベージコレクションされていないのはなぜですか。誰もそのスレッドを参照していません。


16
この答えは、現在のところ、スレッドを(終了後に)GCすることができるかどうかという疑問を提起します。この質問は、の重複としてマークされているので、この1、彼らが終了した後、スレッドは、もはや「ガベージコレクションのルーツ」としてマークされ、したがって、彼らはGCのために到達可能となっていることを言及すべきではありません。
bluenote10 2014

13
最後の文は浸透しています:「なぜあなたのメインスレッドはゴミではないのですか...」。
行列式

そのため、フォローアップとして、破棄されたスレッド(結合されたスレッド)はルートとは見なされなくなりますか?答えは「はい」だとほぼ確信していますが、プロファイラーの下のアプリケーションで奇妙なことが見られ、不思議に思っています...
Groostav 2015年

1
私が読んだ答えが多ければ多いほど、私は混乱しますが、メインスレッドがガベージコレクションを取得していない理由は、考えるべきことです。しかし、コアの質問に戻ると、子スレッドがいくつかのオブジェクトを作成すると、親スレッドがまだ実行されており、子スレッドの参照が「なくなった」場合でも保持されるため、GCされません(!! ??)
Rahul Kumar

@Groostav結合されたスレッドは実行されていないため、ガベージコレクションルートではありません。しかし、親スレッドがを呼び出したときchild.join()、それはへの参照を持っていましたchild。その参照(および他の参照)が破棄されない場合、子スレッドはGCできません。
Blaisorblade 2017年

23

説明したように、実行中のスレッドは、定義上、GCの影響を受けません。GCは、常に到達可能と見なされる「ルート」をスキャンすることから作業を開始します。ルートには、グローバル変数(Javaトークでは「静的フィールド」)と実行中のすべてのスレッドのスタック(実行中のスレッドのスタックが対応するThreadインスタンスを参照していると想像できます)が含まれます。

ただし、スレッドを「デーモン」スレッドにすることはできます(を参照Thread.setDaemon(boolean))。デーモンスレッドは非デーモンスレッドよりもガベージコレクションされませんが、実行中のすべてのスレッドがデーモンになると、JVMは終了します。それを想像する1つの方法は、すべてのスレッドが終了するときに、デーモンを実行していないスレッドが残っているかどうかをチェックすることです。そうでない場合、終了スレッドはSystem.exit()呼び出しを強制し、JVMを終了します(実行中のデーモンスレッドを強制終了します)。これはGC関連の問題ではありません。ある意味で、スレッドは手動で割り当てられます。ただし、これは、JVMがセミローグスレッドを許容する方法です。これは通常、Timerインスタンスに使用されます。


19

JVMには、実行中のすべてのスレッドへの参照があります。

スレッド(またはそれが参照するもの)は、実行中にガベージコレクションされません。


13

表示できないスレッドへの参照があるため、スレッドはガベージコレクションされません。たとえば、ランタイムシステムに参照があります。

スレッドが作成されると、現在のスレッドグループに追加されます。現在のスレッドグループ内のスレッドのリストを取得できるので、それへの参照を取得する別の方法です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.