为了简化事情,假设我在析构函数内有简单的类定义
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();
}
我希望当终结线程处理终结队列时,我的析构函数将被调用一次。
事实上,当我在入口、内部和导出的析构函数方法中放置断点时,我的行为非常奇怪:
- 遇到入口断点
- 然后再次遇到入口断点
- 击中内部断点
- 遇到退出断点
- 然后再次遇到入口断点
第一个想法是两个不同的线程来执行析构函数方法,但是为什么其中一个线程会跳过方法代码并仅在第二次迭代时执行它?一般来说,为什么析构函数被调用两次?
最佳答案
如果您在 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(),这可能是断点第二次停止的地方。
我不确定在那里放置断点的预期行为是什么,但我认为这就是您所看到的原因。
关于c# - 奇怪的析构函数行为,调用两次,但第一次跳过代码执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37879948/