为什么总是调用终结器?
我跑了下面的代码,发现总是调用终结器。但许多文章都说终结者是非决定论的。为什么总是调用终结器?
class Test
{
Test()
{
throw new Exception();
}
~Test()
{
Console.WriteLine("Finalizer is called");
}
static void Main()
{
try
{
new Test();
}
catch { }
}
有些情况下,它可能不会被调用;以及即使被调用也可能无法完成的情况。
垃圾收集器在收集对象时调用终结器。你可以通过调用GC.SuppressFinalize();
Documentation
你可以这样调用里面放上Dispose()
从它的资源已被布置之后收集类停止垃圾收集抑制终结呼叫。
虽然在某些情况下不会调用终结器,但它通常会被调用。最大的问题是何时被调用,因此它是非确定性的。
C#被垃圾收集,垃圾收集器以未指定的间隔运行。因此,如果终结器需要做一些时间敏感的事情,最好使用Dispose而不是终结器。例如,您可能希望立即关闭数据库连接,而不是在等待垃圾收集器时将其保持打开状态。
该代码非常简单,以至于.NET运行时可以在没有问题的情况下运行终结器,但在高负载应用程序中,只有在运行垃圾回收时才会调用终结器。
这里有这篇文章
http://msdn.microsoft.com/en-us/magazine/bb985010.aspx
定稿
垃圾收集器提供您可能希望利用的一个附加功能的摘录:定稿。完成后,资源可以在收集后正常清理。通过使用终结,当垃圾收集器决定释放资源的内存时,表示文件或网络连接的资源能够正确清理自己。
以下是发生了什么过分简化:当垃圾收集器检测到对象是垃圾时,垃圾收集器会调用对象的Finalize方法(如果存在),然后回收对象的内存。例如,假设您有以下类型(C#):
public class BaseObj {
BaseObj() {}
protected override void Finalize() {
// Perform resource cleanup code here...
// Example: Close file/Close network connection
Console.WriteLine("In Finalize.");
}
}
现在你可以创建这个对象的实例,通过调用:
BaseObj bo = new BaseObj();
一些在未来的时间,垃圾收集器将确定这个对象是垃圾。当发生这种情况时,垃圾收集器将看到该类型有一个Finalize方法,并将调用该方法,导致“In Finalize”出现在控制台窗口中并回收此对象使用的内存块。
注意这实际上不合法C# - 在C#中,您必须实现'析构函数'(使用'〜MyClass'语法),而不是重写Finalize(错误CS0249)。 – itowlson 2010-01-18 03:04:48
就你而言,终结器作为应用程序关闭的一部分运行。从the docs:
在应用 域的关机,最后确定是不是从定稿免除 对象自动 调用,即使那些仍然 访问。
非确定性是指当最终确定将被调用。但除特殊情况(如断电或突然死亡的过程)外,最终会调用终结器,即。
在你的情况下它仍然是非确定性的。非确定性意味着事情发生所需的时间量不能预先计算得出。请注意,无法正确确定何时发生并不一定意味着随机时间,但在大多数情况下它们大致相同。
从来不需要控制汽车刹车,工业机器人或航天飞机的人通常不应该在意天气的一段代码是否是确定性的。
注意:我有书面代码来控制工业机器人,所以我有时需要关心我的代码在我想要的时刻执行。
个人而言,我会强调“什么时候”超过“持续时间”(它是如何读取的),但我知道你的意思。 – 2010-01-18 06:45:51
我给出了非确定性的传统定义,其重点在于持续时间,因为持续时间通常在**时确定**。但是,在这种情况下,当调度程序中断正在运行的进程时,它会由**造成更多。 – slebetman 2010-01-18 07:09:21
你跑了几次? “非确定性”不*意味着“你会运行十几次,并且会有一次它不被调用”。 – 2010-01-18 02:55:53
通过不在构造函数中抛出异常,您可能会得到更准确的图片。如果无法正确创建对象,GC或VM始终运行终结器是完全可能的。 – 2010-01-18 02:56:37
不确定你的意思是非确定性的,很确定每当对象被正常处理时都会被调用。也许您提到的其中一篇文章的链接可能会有所帮助。 – 2010-01-18 03:03:10