【问题标题】:Destructor - does it get called if the app crashes析构函数 - 如果应用程序崩溃,它会被调用吗
【发布时间】:2011-01-31 15:55:17
【问题描述】:

如果应用崩溃,是否会调用析构函数?如果这是一个未处理的异常,我猜它确实如此,但是更严重的错误,或者像用户杀死应用程序进程之类的东西呢?

还有一些可能很愚蠢的问题:

  • 当应用程序退出并且所有终结器都已执行时,应用程序中的所有对象会发生什么情况 - 对象是否被垃圾收集,或者它们是否以某种方式全部被进程或应用程序域“卸载”?
  • 是每个应用程序的垃圾收集器部分(在同一进程中运行)还是独立的?

【问题讨论】:

  • 什么样的崩溃?异常不是崩溃,而是可恢复的错误。

标签: c# .net destructor


【解决方案1】:

我鼓励您自己尝试一下。例如:

using System;

class Program {
  static void Main(string[] args) {
    var t = new Test();
    throw new Exception("kaboom");
  }
}
class Test {
  ~Test() { Console.WriteLine("finalizer called"); }
}

在命令提示符下运行此命令,以便您看到最后的喘息。首先将 throw 语句注释掉。

与 Windows 中的任何未处理异常一样,Windows 提供的默认异常过滤器调用由 WerFault.exe 显示的 Windows 错误报告对话框。如果单击“关闭程序”,WerFault 将使用 TerminateProcess() 终止程序。这是一个快速结束,没有机会运行终结器线程,就像程序正常退出时那样。

然后,Windows 会负责清理弹片。它会自动关闭您的程序可能已经打开但没有机会在终结器中关闭的任何操作系统句柄。文件是这里比较棘手的问题,它们的缓冲区不会被刷新,你很容易在磁盘上得到一个部分写入的文件。

【讨论】:

  • +1。谢谢,信息量很大。我一定会尝试一下这个和其他一些想法,看看发生了什么。
【解决方案2】:

如果杀死一个应用程序,该应用程序几乎 100% 会立即失去控制,并且它没有机会调用析构函数。

【讨论】:

    【解决方案3】:

    我什至不懂 C#,但根据我使用其他编程语言的经验,我猜想:如果应用程序崩溃,则意味着它存在严重问题。不正确的内存处理等。在这种情况下,任何编程语言都尝试执行析构函数/释放器/终结器/...是很奇怪的。事情可能会更糟;)

    更新:(忘记尝试回答您的其他问题)再次,不是 C# 特定的,但通常不能保证析构函数/释放器/终结器/...实际上被调用。这样做的原因是,当一个进程退出时,简单地“删除”该进程使用的内存块比运行其析构函数等来清理内存要容易和高效。

    如果不涉及太多技术细节,我不确定如何回答您的最后一个问题。有几种方法可以设计和运行垃圾收集器,最简单的是垃圾收集停止当前进程并在完成后继续它,尽管也有可能(但更难)让垃圾收集器同时运行与正在收集其内存的进程。

    您可能需要阅读垃圾收集理论以更好地理解所有这些。实际上有一个关于这个主题的完整网站:www.memorymanagement.org

    【讨论】:

    • 谢谢,很好的答案。但是一件事似乎不对 - 你说即使应用程序正常退出,一些析构函数仍然可能不会被调用......这对我来说似乎不对,因为垃圾收集器或任何人都没有办法else(但对象本身)知道应用程序的托管对象可能使用了什么样的本机资源,因此它无法处理。无论如何,我会尝试一下,正如 nobugs 所建议的那样,并在我有一点时间时发布结果......
    • 我不能说 C#,但 Objective-C 在这里提供了一个有趣的例子。您应该比较“dealloc”(关闭 GC 时的析构函数)和“finalize”(打开 GC 时)的文档。对于'dealloc',文档非常明确地说不能保证它会被调用,你不应该依赖它来关闭文件。对于“finalize”,文档比较模糊,似乎建议您可以依靠“finalize”作为“备份”来确保文件关闭等,但我找不到明确表示“finalize”的句子是保证会被调用。
    • 这里是 Objective-C 中“dealloc”和“finalize”文档的链接。顺便说一句:虽然只是尝试一个实验来看看这些在 C# 中调用是否很好,但您还应该查看文档。如果您的实验显示它被调用,但文档没有说有 保证,那么这可能会在未来版本或其他平台上更改,因此您最好不要依赖它。 Obj-C 文档。链接:developer.apple.com/mac/library/documentation/Cocoa/Reference/…
    • 我稍微深入研究了 Objective-C 中“finalize”的文档,发现了这句话:“对象最终化在对象的生命周期内最多发生一次——当它被收集时。”请注意,他们不是说“恰好一次”而是“最多一次”,这对我来说意味着它可能是 1 次或 0 次。所以至少在 Objective-C 中,不能保证“finalize”会被调用。我希望大多数其他语言(包括 C#)也是如此,因为不保证允许操作系统或虚拟机在可能的情况下进行更快的内存清理。
    猜你喜欢
    • 2016-09-19
    • 2015-03-13
    • 2015-04-29
    • 2017-06-28
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    相关资源
    最近更新 更多