奇怪的析构函数行为,调用两次,但第一次跳过代码执行

时间:2016-06-17 11:02:04

标签: c# .net garbage-collection destructor

为了简化事情,我们说在

中的析构函数中有简单的类定义
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();
    }

我希望在终结线程处理终结队列时,我的析构函数会被调用一次。

事实上,当我在我的析构函数方法中将断点放在入口,内部和退出时,我有非常奇怪的行为:

  1. 输入分界点
  2. 然后再次进入破发点
  3. 内部断点被击中
  4. 点击退出断点
  5. 然后再次进入破发点
  6. 第一个想法是两个不同的线程来执行析构函数方法,但是为什么其中一个跳过方法代码并且只在第二次迭代时执行它?一般来说为什么desctructor被调用两次?

1 个答案:

答案 0 :(得分:2)

如果您在ILSpy中打开代码,您会看到:

protected override void Finalize()
{
    try
    {
        string breakPoint = string.Empty;
    }
    finally
    {
        base.Finalize();
    }
}

我希望通过打开开启和关闭的大括号,您会看到多个“代码行”正在执行,这些代码行与打开和关闭大括号相关联的代码行相关联。即trybase.Finalize()来电。

在原始IL中,代码的结尾部分如下所示:

finally
{
    IL_000a: ldarg.0
    IL_000b: call instance void [mscorlib]System.Object::Finalize()
    IL_0010: nop
    IL_0011: endfinally
} //

它调用Object :: Finalize(),这可能是你的断点第二次停止的地方。

我不确定在那里放置断点的预期行为是什么,但我认为这是你所看到的原因。