是否存在垃圾收集器由于异常而无法运行的情况?

时间:2013-03-06 13:09:28

标签: c# garbage-collection

出于好奇,我想知道是否有可能出现垃圾收集器无法运行或根本不运行的情况(可能是由于异常)?

如果是,很可能会出现OutOfMemory / Stackoverflow异常。那么在这种情况下,通过查看异常消息,stacktrace等,我们可以确定gc无法运行的核心问题。

4 个答案:

答案 0 :(得分:5)

正如其他人所提到的,许多事情都可能阻止GC运行。 FailFast快速失败;在拆除建筑物之前,它不会停下来取出垃圾。但你具体询问了例外情况。

未捕获的异常产生实现定义的行为,因此它是实现定义的,无论是否运行finally块,是否运行垃圾收集,以及是否在存在未捕获的异常时终结终结器队列对象。 CLR的实现允许在发生任何事情时执行任何操作,并且"任何事情"包括"运行GC"并且"不运行GC"。事实上,CLR的实施已经改变了他们的行为;在CLR的v1.0中,终结器线程上的未捕获异常取消了该过程,在v2.0中捕获了终结器线程上的未捕获异常,记录了错误,并且终结器继续运行。

答案 1 :(得分:1)

有四个感兴趣的问题:

  • 可能会导致程序完全死亡,垃圾收集器无法运行

  • 可以阻止垃圾收集器运行而不会导致系统完全死亡

  • 可以阻止对象的终结器运行而不会导致系统完全死亡

  • 异常可以使对象在任意时间段内无法收集

关于第一个,答案是“绝对”。有很多方法可能会发生,没有必要在这里列出它们。

关于第二个问题,答案是“一般都没有”,因为垃圾收集器的失败会使程序瘫痪;但是,在某些情况下,即使使用托管对象的部分可能被无限期阻止,不使用GC管理的内存的程序部分也可能继续运行。

关于第三个问题,过去在.net中,终结器中的异常可能会干扰其他终结器的操作而不会杀死整个应用程序;自.net 2.0以来这种行为已经改变,因此从终结器抛出的未捕获的异常通常会杀死整个程序。但是,有可能在一个写得不好的终结器中抛出并捕获的异常可能导致它无法清理它应该的所有内容,导致问题#4。

关于第四个问题,对象在创建时对自己建立长期(可能是静态的)引用是很常见的,并且它们会将这些引用作为清理代码的一部分进行销毁。如果异常阻止清理代码按预期运行,则可能导致对象变得无法收集,即使它们不再有用。

答案 2 :(得分:0)

是的,在Java中曾经存在这样的情况:程序可以在没有GC最后一次运行的情况下停止 - 在大多数情况下这是正常的,因为当程序的堆被破坏时所有内存都被清除了,但是你可能会遇到没有终结者被运行的对象的问题,这对你来说可能是也可能不是问题,这取决于那些终结者会做什么。

我怀疑你是否能够确定GC失败,因为程序将像鹦鹉一样死,以非干净的方式,所以你可能甚至不会得到堆栈跟踪。您可能能够对其进行事后调试(如果您已经启用了正确的dbg设置,那么在使用优秀的Windows调试工具时,.NET就可以了。)

答案 3 :(得分:0)

某些边缘情况会导致finally块无法执行 - 调用FailFast是一种情况,并且其他人会看到问题here

鉴于此,我认为有些情况(特别是在using语句/ IDisposable对象中)不会执行finally块中发生的资源清理/垃圾收集。< / p>

更明确地说,像这样:

try
{
    //new up an expensive object, maybe one that uses native resources
    Environment.FailFast(string.Empty);
}
finally
{
    Console.WriteLine("never executed");
}