我运行了以下代码,发现始终调用终结器。但很多文章都说终结者是非决定性的。
class Test
{
Test()
{
throw new Exception();
}
~Test()
{
Console.WriteLine("Finalizer is called");
}
static void Main()
{
try
{
new Test();
}
catch { }
}
答案 0 :(得分:4)
在您的情况下,它仍然是不确定的。非确定性意味着某些事情发生所需的时间无法预先计算。请注意,无法正确确定何时会发生某些事情并不一定意味着随机时间,但在大多数情况下它们大致相同。
从不需要控制汽车制动器,工业机器人或航天飞机的人一般不应该关心天气的一段代码是否具有确定性。
注意:我有编写的代码来控制工业机器人,所以我有时需要关心我想要的确切时刻执行的代码。
答案 1 :(得分:1)
垃圾收集器在收集对象时调用终结器。您可以致电GC.SuppressFinalize();
Documentation
您可以将此调用置于Dispose()
内,以阻止垃圾收集器在其资源被处理后收集该类。
答案 2 :(得分:1)
在您的情况下,终结器正在作为应用程序关闭的一部分运行。来自the docs:
在关闭应用程序期间 域名,自动完成 调用不可豁免的对象 从最终确定,即使是那些 仍然可以访问。
非确定性是指何时将调用 Finalize。但除非在特殊情况下(例如电源被切断或进程突然被杀死),终结器最终将被调用。
答案 3 :(得分:0)
有些情况可能无法调用;以及即使被调用的情况,也可能不允许完成。
答案 4 :(得分:0)
虽然在某些情况下不会调用终结器,但通常会调用终结器。最重要的问题是它何时被调用,因此它是非确定性的。
C#被垃圾收集,垃圾收集器以未指定的间隔运行。因此,如果终结器需要做一些时间敏感的事情,最好使用Dispose而不是终结器。例如,您可能希望立即关闭数据库连接,而不是在等待垃圾收集器时将其保持打开状态。
答案 5 :(得分:0)
该代码非常简单,.NET Runtime可以在没有问题的情况下运行终结器,但在高负载应用程序中,只有在垃圾收集运行时才会调用终结器。
这里有一篇本文的摘录
http://msdn.microsoft.com/en-us/magazine/bb985010.aspx
<强>最后确定强>
垃圾收集器提供了一个额外的功能,您可能希望利用它:完成。完成后,资源可以在收集资源后自行清理。通过使用finalization,当垃圾收集器决定释放资源的内存时,表示文件或网络连接的资源能够正确清理自己。
以下是对发生的事情的过度简化:当垃圾收集器检测到对象是垃圾时,垃圾收集器调用对象的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”出现在控制台窗口中并回收此对象使用的内存块。