是否有可能在类的析构函数中调用GC实现了IDisposable?

时间:2013-12-09 04:51:12

标签: c# .net memory memory-leaks garbage-collection

----------- ---------- EDIT1

对不起我的英语很差,似乎原来的问题对很多人来说都没有意义,所以我把问题大大简化为两句话:

IDisposable pattern in MSDN的msdn代码示例中,在析构函数中释放未管理的资源代码是为了当用户忘记调用Dispose()来释放资源时,GC仍然可以帮助至少释放未受管理的资源,但是,当一个类使用一些未受管理的资源时,它必须(隐式或显式地)将当前实例(或字段)注册到GC句柄表,然后永远不会被GCed,所以代码如何析构函数在这种情况下执行了吗?

-----------结束Edit1 -------

我们知道着名的IDisposable模式,可以在网上看到很多:IDisposable pattern in MSDN

在样本中,据我所知,析构函数的用途适用于此案例:如果用户忘记明确调用Dispose(),则 GC将帮助并释放未受管理的资源。

但我只是想知道在任何情况下析构函数都可以通过GC 调用而不用用户代码先显式调用Dispose()吗?

猜测是基于实现IDisposable的原因并且有一个明确的析构函数:

此类使用了一些未管理的资源。无论是P / Invoke还是托管API(BCL),据我所知,两种方式都需要在GC句柄表中添加 GC句柄条目避免 GCed,因此析构函数不会被GC调用。

所以我们永远不要指望资源自动释放运气?为什么把它放在示例代码中?

2 个答案:

答案 0 :(得分:3)

这里有很多问题。让我们试着回答所有问题。

  

在MSDN代码中,释放非托管资源的IDisposable模式代码的样本放在析构函数中。这可确保当用户忘记调用Dispose()以释放资源时,GC仍会释放非托管资源。

正确。

  

但是当一个类使用一些非托管资源时,它必须将当前实例注册到GC句柄表,然后永远不会被GCed。

我不明白这句话。您所说的“GC句柄表”是什么?

您能展示一些演示您的方案的示例代码吗?

  

在这种情况下,析构函数中的代码如何执行?

简要地说,GC的工作原理如下。 GC知道“根”;这些是绝对活着的参考。 GC首先将所有对象标记为已死。然后它标志着生根。然后它将根所指的所有内容标记为活着,然后将每个他们称为活着,依此类推。那是从根目录可以访问的所有内容。然后GC杀死所有仍被标记为死亡的东西。

现在,如果一个死对象可以最终化 - 如果它有一个尚未运行的析构函数 - 那么GC不会杀死该对象。该对象被放在要最终确定的对象列表中,并且该列表是根,因此该对象再次存活。稍后,另一个线程运行终结队列中每个对象的析构函数,并将它们从队列中删除,并将它们标记为不再需要完成。

下次GC运行时,如果对象仍然死亡,则会收集该对象,并且不会再次运行终结器。

  

GC是否可以调用析构函数,而用户代码不会先显式调用Dispose()

是。这就是析构函数的重点。

答案 1 :(得分:2)

GC使用一种称为终结的机制来处理实现IDisposable的类。

如果你正确地实现了这个类,那么当没有调用Dispose时,GC将在超出范围时处理该对象,并且GC将调用终结器。终结器被隐式调用,并且在不可预测的时间调用。

更多技术细节可以从诸如CLR之类的书籍中通过C#或诸如http://msdn.microsoft.com/en-us/magazine/cc163392.aspx

等文章找到