----------- ---------- 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调用。
所以我们永远不要指望资源自动释放运气?为什么把它放在示例代码中?
答案 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
等文章找到