为了简化事情,我们说在
中的析构函数中有简单的类定义public class MyDisposeFinalize
{
~MyDisposeFinalize()
{
var breakPoint = string.Empty;
}
}
在Main
方法中,我首先创建MyDisposeFinalize
类的实例,然后将null
分配给我的实例并调用垃圾回收。
static void Main(string[] args)
{
var myDispose = new MyDisposeFinalize();
myDispose = null;
GC.Collect();
System.Console.ReadKey();
}
我希望在终结线程处理终结队列时,我的析构函数会被调用一次。
事实上,当我在我的析构函数方法中将断点放在入口,内部和退出时,我有非常奇怪的行为:
第一个想法是两个不同的线程来执行析构函数方法,但是为什么其中一个跳过方法代码并且只在第二次迭代时执行它?一般来说为什么desctructor被调用两次?
答案 0 :(得分:2)
如果您在ILSpy中打开代码,您会看到:
protected override void Finalize()
{
try
{
string breakPoint = string.Empty;
}
finally
{
base.Finalize();
}
}
我希望通过打开开启和关闭的大括号,您会看到多个“代码行”正在执行,这些代码行与打开和关闭大括号相关联的代码行相关联。即try
和base.Finalize()
来电。
在原始IL中,代码的结尾部分如下所示:
finally
{
IL_000a: ldarg.0
IL_000b: call instance void [mscorlib]System.Object::Finalize()
IL_0010: nop
IL_0011: endfinally
} //
它调用Object :: Finalize(),这可能是你的断点第二次停止的地方。
我不确定在那里放置断点的预期行为是什么,但我认为这是你所看到的原因。