web-dev-qa-db-ja.com

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

この質問はいくつかのサイトに投稿されました。私はそこに正しい答えを見つけられなかったので、ここに再び投稿しています。

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は、スレッド参照をヌルにします。そのため、JVMには、参照が存在しないスレッドオブジェクト(実行状態)があります(行Bのt = nullとして)。私の質問は、メインスレッドが実行されるまで、なぜこのスレッド(メインスレッドにもう参照がない)が実行され続けるのかということです。私の理解では、スレッドオブジェクトは行B後にガベージコレクションされているはずです。このコードを5分以上実行して、Java Runtimeを実行してGCを実行しようとしましたが、スレッドはやめる。

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

82
Ashish

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

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

117
falstro

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

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

22
Thomas Pornin

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

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

18
Thilo

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

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

11
vy32