新线程和垃圾回收机制

20

我有以下代码:

new Thread(new ThreadStart(delegate()
{
    while (true)
    {
        //something
    }
})).Start();

当线程处于“运行”状态时,垃圾回收器能够完成该线程实例的终结吗?

4个回答

26

CLR会跟踪所有运行中的线程。只要对象有引用,它们就不会被垃圾回收。由于CLR保留了对所有运行中线程的引用,因此GC不会触及它们。


15

不会的,运行中的线程被视为根。正在运行的线程不会被垃圾收集器回收,也不会回收该线程的堆栈的活动部分引用的任何内容。


线程的运行计数算作根吗?或者说,线程内引用对象的引用是否被算作根? - Royi Namir
1
@Royi roots - 基本上是堆栈局部变量。请注意,arg0(又名this)通常也会保持目标实例的存活。 - Marc Gravell
那么说“_GC不允许收集正在运行的线程_”是错误的/可以的吗? - Royi Namir
@Royi 嗯,实际上线程本身并不是托管对象。Thread 类型主要是一个工具,用于帮助与 CLI 线程通信,有时与操作系统线程的 1:1 映射相对应,有时则不是(例如 SQL Server)。 - Marc Gravell
抱歉,我在谈论托管线程。如果线程内没有根节点,gc是否允许收集该线程? - Royi Namir
1
@Royi 这没什么意义。这里唯一受控的是Thread,但它并不是指的“线程”。Thread本身没有所谓的“内部内容”。然而,线程是个根对象,并且不可回收。Thread是否可回收是一个实现细节。 - Marc Gravell

3

线程不会被回收,因为每个正在运行、等待或挂起的线程本身都被垃圾回收器用于判断什么是活动对象(追踪每个线程堆栈中的所有内容,追踪这些对象引用的所有内容,然后追踪这些内容引用的所有内容,依此类推,就能确定哪些内容不能被回收)。

如果线程是后台线程,则可能会结束,因为当进程中的所有其他线程完成时,后台线程将被主动关闭。否则,唯一会导致其停止的原因是进程被主动退出、异常(包括ThreadAbortException)或者线程自己跳出while循环。

有一个类似的情况,在某些方面是可比较的,也许这就是你想要的:

var timer = new System.Threading.Timer(someCallback, null, new TimeSpan(0, 0, 5), new TimeSpan(0, 0, 5));
int someResult = doingSomethingElse();
doSomethingElseThatTakesLongerThan5Seconds();

这是另一段代码,它会导致另一个执行线程执行某些操作。在这种情况下,计时器确实可以在运行之前、运行期间或构造函数返回后的任何时间被垃圾回收。
重要的是,这里没有单独的计时器线程,线程甚至不知道计时器对象的存在。由于该对象的最后访问已经发生,因此它有资格进行回收。这与正在运行(或等待等)的单个线程的问题不同。

1
所有正在运行的计时器、线程、线程池和任务都被标记为根对象。因此,只有当它们完成执行或应用程序关闭时才会被垃圾收集器回收或删除。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接