Java:为什么不收集垃圾?

Java:为什么不收集垃圾?,java,garbage-collection,Java,Garbage Collection,关于GCing理论的快速问题。我有以下方法。它运行并退出该方法。为什么即使在GC运行之后,计时器仍然存在并保持“滴答”声?我不相信在这个方法存在之后,仍然存在对计时器或timertask的引用,所以我希望计时器被GCed并导致异常。请帮助我理解这个概念 谢谢, jbu 你怎么知道GC在运行?垃圾收集通常不是一个确定性的东西,它肯定不是由方法范围触发的。不像C++那样,函数的作用域和析构函数会被烧掉。如果GC愿意,它将开始收集该内存。该对象实际上在后台线程中安排要执行的任务,以便后台线程维护对计时

关于GCing理论的快速问题。我有以下方法。它运行并退出该方法。为什么即使在GC运行之后,计时器仍然存在并保持“滴答”声?我不相信在这个方法存在之后,仍然存在对计时器或timertask的引用,所以我希望计时器被GCed并导致异常。请帮助我理解这个概念

谢谢, jbu


你怎么知道GC在运行?垃圾收集通常不是一个确定性的东西,它肯定不是由方法范围触发的。不像C++那样,函数的作用域和析构函数会被烧掉。如果GC愿意,它将开始收集该内存。

该对象实际上在后台线程中安排要执行的任务,以便后台线程维护对计时器(和TimerTask)的引用,从而防止两者被垃圾收集

以下是文件中的适当报价:

在最后一次实时引用 计时器对象消失,所有 尚未完成的任务已经完成 执行,计时器的任务执行 线程优雅地终止(并且 成为垃圾的对象 收藏)。然而,这可能需要更长的时间 任意长时间发生。默认情况下, 任务执行线程未运行 作为守护进程线程,因此它能够 阻止申请者 终止。如果打电话的人想 终止计时器的任务执行 快速线程,调用方应该 调用计时器的cancel方法


因此“所有未完成的任务都已完成执行”的条件不满足,线程从不终止,因此计时器/TimerTask从不被GC'd。

计时器没有被垃圾收集,因为它仍在运行——其他一些对象(如线程调度程序)仍有对它的引用,这可能是在scheduleAtFixedRate()中创建的,因为计时器具有:

对应于每个计时器对象的是 一个单独的背景线程 用于执行所有计时器的 任务,按顺序。计时器任务 应该很快完成。如果有计时器 这项任务需要过多的时间才能完成, 它“占用”计时器的任务执行 线反过来,这又会延迟时间 执行后续任务,其中 可以“聚集”并快速执行 当(和如果)违规者 任务终于完成了

因为它是一个后台线程,所以它一直持续到JVM退出或停止

更新:更多关于这方面的信息。“后台线程”与守护进程线程是一样的——类似于BSD守护进程进程而命名。如果您在上看到javadocs,您将发现:

将此线程标记为守护进程或 线程或用户线程。爪哇 当只有 运行的线程都是守护进程 线程

当主线程终止时,所有用户线程都停止,只留下守护进程线程。JVM随后关闭。如果时间很短,则调用
Thread.currentThread().setDaemon(true)来自main

更新:确认。我几乎是对的。必须在构造时将计时器设为守护进程。(这种情况改变了吗,还是我只是因为脑功能衰竭?)

无论如何,下面是示例代码:

import java.util.*;

class Chatter extends TimerTask {
    public void run(){
        System.err.println("Timer run.");
    }
}

public class TryThread {
    public static void main(String[] argv){
        // If argument is true, only runs a few times.
        Timer t = new Timer(false);
        t.schedule(new Chatter(), 1L, 1L);
        return ;
    }
}

我已经通过netbeans.com的调试模式显式调用了GC。来自Timer的JavaDocs:“与每个Timer对象相对应的是一个后台线程,用于按顺序执行计时器的所有任务。”然而,如果我取消计时器,计时器/TimerTask最终将被GC?只是为了强调Charlie的观点,活动线程是垃圾收集器的“根”对象。它们在死之前不是垃圾,不能被收集。任何可以从活动线程进行强引用的东西也不是垃圾。加载的类也以类似的方式工作。等等,那么这个计时器即使在调用它的程序完成后也可以继续执行吗?不,因为当在开始时调用的公共静态void main终止时,JVM将整体关闭,这意味着停止并杀死后台线程。但它并没有真正得到GC,因为当进程死亡时,所有内存都被释放。@Charlie Martin:只有在没有其他非守护进程线程的情况下才是这样。例如,Swing应用程序通常都有一个main(),它只调用GUI并终止。正如Rick Copeland在回答中引用的Javadoc所解释的那样,计时器确实可以防止JVM退出。两个不同的程序可以在同一个JVM中运行吗?或者是一个程序=一个JVM?如果它真的消失了,不是很可怕吗?这将使几乎所有的多任务处理变得更加困难。
import java.util.*;

class Chatter extends TimerTask {
    public void run(){
        System.err.println("Timer run.");
    }
}

public class TryThread {
    public static void main(String[] argv){
        // If argument is true, only runs a few times.
        Timer t = new Timer(false);
        t.schedule(new Chatter(), 1L, 1L);
        return ;
    }
}