问题描述
根据我的所有阅读,应该有一个 GC 线程来调用所有终结器.现在,问题是这个一个"线程的范围是什么——每个进程或每个应用程序域,因为域的整体意图是在一个进程空间中分离和制作独立"的不同应用程序.
Based on all my reading there should be one GC thread to invoke all finalizers. Now, the question is what is the scope of this "one" thread - per process or per application domain, as the whole intention of domains is to separate and make "independent" different applications in one process space.
我在这里阅读:
如果一个未处理的异常发生在终结 CLR 的执行线程将吞下异常,对待终结器就好像它正常完成一样,将其从可访问队列中删除并移至下一个条目.
更严重的是,会发生什么如果您的终结器没有退出某种原因,例如它阻塞,等待一个永远不会的条件发生.在这种情况下终结器线程将被挂起,所以没有更多可终结的对象将是垃圾收集.你应该非常意识到这种情况并坚持编写最简单的代码来释放你的终结器中的非托管资源.
More serious though, is what happens if your finalizer doesn't exit for some reason, for example it blocks, waiting for a condition that never occurs. In this case the finalizer thread will be hung, so no more finalizable objects will be garbage collected. You should be very much aware of this situation and stick to writing the simplest code to free your unmanaged resources in finalizers.
另一个考虑是会发生什么在应用程序关闭期间.当...的时候程序关闭,垃圾收集器将努力调用终结者所有可终结的对象,但与某些限制:
Another consideration is what happens during application shutdown. When the program shuts, the garbage collector will endeavour to call the finalizers of all finalizable objects, but with certain limitations:
不提升可终结对象到更高的堆世代关闭.
Finalizable objects are not promoted to higher heap generations during shutdown.
任何一个终结器都会有一个最多执行 2 秒;如果它它需要更长的时间才能被杀死.
Any individual finalizer will have a maximum of 2 seconds to execute; if it takes longer it will be killed off.
最长为 40 秒要执行的所有终结器;如果有的话终结器仍在执行,或此时整个待定进程被突然终止.
There is a maximum of 40 seconds for all finalizers to be executed; if any finalizers are still executing, or pending at this point the whole process is abruptly killed off.
太多帖子(甚至官方文档)滥用了术语应用程序"、进程"和应用程序域"——他们中的大多数甚至假设它们是平等的,因为通常应用程序在单个应用程序域中运行一个进程.这种误用使所有这些文档都难以阅读,甚至毫无用处.
Too many posts (and even official documentation) misuse of the terms "application", "process" and "application domain" - most of them even assuming that they are equal, because usually applications are run in a single application domain in a single process. This misuse makes all of these docs hard to read, and not even useful.
因此,我的问题假设有多个应用程序,每个应用程序都在单个进程中的单独应用程序域中运行.
So, my question assumes more than one applications, each run in a separate application domain in a single process.
所有这些应用程序是否共享相同的 GC 和终结器线程?上面文章中描述的问题(挂起终结器线程)是否会影响该进程中的所有应用程序?如果是 - 是否有解决方法(除了不使用不良应用程序),例如以某种方式发现终结器线程并将其发送 Thread.Abort?
Does all these application share the same GC and finalizer threads? Does the problem described in the article above (hang finalizer thread) will affect all applications in that process? If yes - is there a workaround (besides to not use bad applications), like somehow to discover the finalizer thread and send it Thread.Abort?
以上都是因为我遇到了类似的问题.我的应用程序作为第三方软件 (Outlook) 的插件在单独的应用程序域中运行.由于各种原因,我需要调用 GC.Collect 和 GC.WaitForPendingFinalizers 来完全释放 COM 引用(通常的互操作例程对于 Office/Outlook 来说是不够的),当特定的其他第三方插件正在运行时,我的 GC.WaitForPendingFinalizers 永远挂起,所以我怀疑该第三方添加中存在坏"终结器.我无法控制替换/删除添加(客户的要求),所以我必须自己弄清楚如何让它们共存.
All above is because I hit similar problem. My application runs in a separate application domain as addin to third party software (Outlook). Because of various reasons I need to call GC.Collect and GC.WaitForPendingFinalizers to fully release COM references (the usual interop routines are not enough for Office/Outlook), when a particular other third party addin is running, my GC.WaitForPendingFinalizers hangs forever, so I suspect that there is a "bad" finalizer in that third party adding. I have no control over replacing/removing that adding (client's requirement), so I have to figure out on my own how to make them co-exist.
推荐答案
看起来它确实只是进程中每个 CLR 实例的一个线程 - 无论如何,目前.下面是一些代码来表明:
Looks like it is indeed just one thread per CLR instance within the process - at the moment, anyway. Here's some code to show that:
Test.cs:
using System;
class Test
{
static void Main()
{
AppDomain.CreateDomain("First")
.ExecuteAssembly("ShowFinalizerThread.exe");
AppDomain.CreateDomain("Second")
.ExecuteAssembly("ShowFinalizerThread.exe");
}
}
ShowFinalizerThread.cs:
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).您会看到一个应用域的终结器阻止了另一个.
Compile each as a console app, then run test.exe (from the command line is easiest, IMO). You'll see that one app domain's finalizer blocks another.
在未来,我不会惊讶地看到每个 核心 有一个终结器线程,而不是每个 AppDomain - 但听起来你仍然会遇到问题:(
In the future I wouldn't be surprised to see one finalizer thread per core rather than per AppDomain - but it sounds like you'll still have problems :(
你有我最深切的同情(虽然不是解决方案) - 一旦我在 Oracle Blob 中找到了一个僵局.我们能够通过正确处理它来解决这个问题,但我知道并不是所有的东西都能很好地工作 - 即使找到那个也真的很痛苦!
You have my deepest sympathy (though not a solution) - once I tracked down a deadlock in an Oracle Blob. We were able to fix that by disposing of it properly, but I know not everything works that nicely - and it was a real pain even finding that one!
这篇关于终结器线程的范围是什么 - 每个应用程序域或每个进程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!