这是显示出令人惊讶的终结行为的示例程序:
class Something
{
public void DoSomething()
{
Console.WriteLine("Doing something");
}
~Something()
{
Console.WriteLine("Called finalizer");
}
}
namespace TestGC
{
class Program
{
static void Main(string[] args)
{
var s = new Something();
s.DoSomething();
GC.Collect();
//GC.WaitForPendingFinalizers();
s.DoSomething();
Console.ReadKey();
}
}
}
如果我运行程序,打印出来的是:
Doing something
Doing something
Called finalizer
这似乎符合预期。因为在调用
GC.Collect()
之后有对 s 的引用,所以 s 不是垃圾。现在从
//GC.WaitForPendingFinalizers();
行中删除注释再次构建并运行程序。
我希望输出不会发生任何变化。这是因为我读到 如果发现对象是垃圾并且它有一个终结器,它将被放入终结器队列 。由于对象不是垃圾,因此不应将其放入终结器队列似乎是合乎逻辑的。因此,注释掉的行应该什么都不做。
但是,程序的输出是:
Doing something
Called finalizer
Doing something
有人可以帮助我理解为什么调用终结器吗?
最佳答案
我无法在笔记本电脑上重现该问题,但您的 DoSomething
方法不使用对象中的任何字段。这意味着即使 DoSomething
正在运行,对象也可以被最终确定。
如果您将代码更改为:
class Something
{
int x = 10;
public void DoSomething()
{
x++;
Console.WriteLine("Doing something");
Console.WriteLine("x = {0}", x);
}
~Something()
{
Console.WriteLine("Called finalizer");
}
}
...然后我怀疑你总是会看到
DoingSomething
在“Called finalizer”之前打印两次——尽管最终的“x = 12”可能在“Called finalizer”之后打印。基本上,终结器可能有点令人惊讶——我很少发现自己使用它,并鼓励您尽可能避免使用终结器。
关于c# - 为什么在对象上调用终结器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20731667/