终结器线程的范围是啥 - 每个应用程序域或每个进程?
Posted
技术标签:
【中文标题】终结器线程的范围是啥 - 每个应用程序域或每个进程?【英文标题】:What is the scope of finalizer thread - per application domain or per process?终结器线程的范围是什么 - 每个应用程序域或每个进程? 【发布时间】:2008-10-27 22:04:26 【问题描述】:根据我所有的阅读,应该有一个 GC 线程来调用所有终结器。现在,问题是这个“一个”线程的范围是什么 - 每个进程或每个应用程序域,因为域的全部意图是在一个进程空间中分离并制作“独立”不同的应用程序。
我读到here:
如果一个未处理的异常发生在 终结 CLR 的执行线程 会吞下异常,对待 终结器就好像它正常完成一样, 从易碎队列中删除它 然后进入下一个条目。
更严重的是,会发生什么 如果你的终结器没有退出 某些原因,例如它阻塞, 等待一个永远不会的条件 发生。 在这种情况下,终结器 线程将被挂起,所以不再 可终结的对象将是垃圾 收集。你应该非常 意识到这种情况并坚持 编写最简单的代码来释放你的 终结器中的非托管资源。
另一个考虑是发生了什么 在应用程序关闭期间。当。。。的时候 程序关闭,垃圾收集器 将努力调用终结者 所有可终结的对象,但与 某些限制:
不提升可终结对象 到更高的堆代期间 关机。
任何单独的终结器都会有一个 最多执行 2 秒;如果它 需要更长的时间才会被杀死。
最多 40 秒 所有要执行的终结器;如果有的话 终结器仍在执行,或 在这一点上悬而未决 进程被突然终止。
太多帖子(甚至官方文档)滥用术语“应用程序”、“进程”和“应用程序域”——其中大多数甚至假设它们是相等的,因为通常应用程序在单个应用程序域中运行一个进程。这种滥用使所有这些文档都难以阅读,甚至没有用处。
因此,我的问题假设有多个应用程序,每个应用程序都在单个进程的单独应用程序域中运行。
所有这些应用程序是否共享相同的 GC 和终结器线程?上面文章中描述的问题(挂起终结器线程)会影响该进程中的所有应用程序吗?如果是 - 是否有解决方法(除了不使用不良应用程序),例如以某种方式发现终结器线程并将其发送 Thread.Abort?
以上都是因为我遇到了类似的问题。我的应用程序作为第三方软件 (Outlook) 的插件在单独的应用程序域中运行。由于各种原因,我需要调用 GC.Collect 和 GC.WaitForPendingFinalizers 来完全释放 COM 引用(通常的互操作例程对于 Office/Outlook 来说是不够的),当某个特定的其他第三方插件运行时,我的 GC.WaitForPendingFinalizers 永远挂起,所以我怀疑第三方添加中有一个“坏”的终结器。我无法控制替换/删除添加(客户的要求),所以我必须自己弄清楚如何使它们共存。
【问题讨论】:
+1 以获得清晰而详细的问题 【参考方案1】:看起来它确实只是进程中每个 CLR 实例的一个线程 - 无论如何,目前。下面是一些代码来说明这一点:
Test.cs:
using System;
class Test
static void Main()
AppDomain.CreateDomain("First")
.ExecuteAssembly("ShowFinalizerThread.exe");
AppDomain.CreateDomain("Second")
.ExecuteAssembly("ShowFinalizerThread.exe");
ShowFinalizerThread.cs:
using System;
using System.Threading;
class ShowFinalizerThread
static Random rng = new Random();
~ShowFinalizerThread()
Console.WriteLine("Thread/domain: 0/1",
Thread.CurrentThread.ManagedThreadId,
AppDomain.CurrentDomain.FriendlyName);
if (rng.Next(10) == 0)
Console.WriteLine("Hanging!");
Thread.Sleep(2000);
static void Main()
new Thread(LoopForever).Start();
static void LoopForever()
while (true)
new ShowFinalizerThread();
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(300);
;
将每个程序编译为控制台应用程序,然后运行 test.exe(从命令行最简单,IMO)。您会看到一个应用域的终结器阻塞了另一个。
将来如果每个 core 而不是每个 AppDomain 都有一个终结器线程,我不会感到惊讶 - 但听起来你仍然会遇到问题 :(
你有我最深切的同情(虽然不是解决方案) - 一旦我在 Oracle Blob 中找到了一个死锁。我们能够通过妥善处理它来解决这个问题,但我知道并非所有东西都能很好地工作——即使找到那个也真的很痛苦!
【讨论】:
我相信每个 CLR 实例一个线程。从 2.0 和 silverlight 开始,每个进程现在可以拥有多个 CLR。 @JaredPar - 你是对的...CLR Inside Out: In-Process Side-by-Side @JonSkeet,关于每个内核一个终结器线程,现在在 2012 年,他们做到了吗? @RoyiNamir:不知道,恐怕。以上是关于终结器线程的范围是啥 - 每个应用程序域或每个进程?的主要内容,如果未能解决你的问题,请参考以下文章