【问题标题】:Java Thread Garbage collected or notJava 线程垃圾是否收集
【发布时间】:2011-01-26 06:25:56
【问题描述】:

这个问题发布在某个网站上。我没有在那里找到正确的答案,所以我再次在这里发布。

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 运行时运行 GC,但线程并没有停止。

希望这次代码和问题都清楚。

【问题讨论】:

    标签: java multithreading garbage-collection


    【解决方案1】:

    JVM 对所有正在运行的线程都有一个引用。

    当线程仍在运行时,不会对线程(或它所指的事物)进行垃圾收集。

    【讨论】:

      【解决方案2】:

      正在运行的线程被认为是所谓的垃圾收集根,是防止垃圾收集的东西之一。当垃圾收集器确定您的对象是否为“reachable”时,它总是使用垃圾收集器根集作为参考点。

      考虑一下,为什么你的主线程没有被垃圾收集,也没有人引用那个。

      【讨论】:

      • 这个答案,就目前而言,提出了线程是否可以被 GC 的问题(在它们终止之后)。由于此问题被标记为与this one 重复,需要说明的是线程终止后将不再被标记为“垃圾收集根”,因此它们可以被 GC 访问。
      • 最后一句话很有穿透力:“为什么你的主线程不是垃圾……”。
      • 那么作为后续,一个已处理的线程(已加入的线程)是否不再被视为根?我几乎可以肯定答案是肯定的,但我在探查器下的应用程序上看到了奇怪的东西,这让我想知道......
      • 我读的答案越多,我就越困惑,但是是的,为什么主线程没有收集垃圾是值得思考的。但回到核心问题,如果子线程创建了一些对象,它不会被 GC,因为父线程仍在运行并持有子线程的引用,即使它们已经“用完”(!!??)
      • @Groostav 已加入的线程未运行,因此它不是垃圾收集根。但是当父线程调用child.join() 时,它引用了child。如果该引用(以及任何其他引用)未被丢弃,则子线程无法被 GC。
      【解决方案3】:

      线程没有被垃圾回收,因为存在对您看不到的线程的引用。例如,运行时系统中有引用。

      当线程被创建时,它被添加到当前线程组中。您可以获取当前线程组中的线程列表,这是获取对它的引用的另一种方式。

      【讨论】:

        【解决方案4】:

        如前所述,根据定义,正在运行的线程不受 GC 的影响。 GC 通过扫描“根”开始其工作,这些“根”被认为始终可以访问;根包括全局变量(Java-talk 中的“静态字段”)和所有正在运行的线程的堆栈(可以想象一个正在运行的线程的堆栈引用了对应的Thread 实例)。

        但是,您可以使线程成为“守护程序”线程(请参阅Thread.setDaemon(boolean))。守护线程不会比非守护线程更垃圾收集,但是当所有正在运行的线程都是守护线程时,JVM 会退出。一种想象的方法是,每个线程在终止时都会检查是否还有一些非守护程序正在运行的线程;如果没有,终止线程会强制执行System.exit() 调用,该调用会退出 JVM(杀死正在运行的守护程序线程)。这不是与 GC 相关的问题;在某种程度上,线程是手动分配的。但是,这就是 JVM 可以容忍半流氓线程的方式。这通常用于Timer 实例。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-13
          • 1970-01-01
          相关资源
          最近更新 更多