为什么 Dispose() 应该处理托管资源而不是终结器?

Why should Dispose() dispose managed resources and finalizer not?

我们都知道 System.IDisposable 模式。它被描述了无数次,也在 Whosebug 上:

link: Dispose() for cleaning up managed resources?

The Disposable patterns advises that I should only dispose managed resources if my object is being disposed, not during finalize

您可以看到出现这种情况是因为建议使用以下代码:

protected void Dispose(bool disposing)
{
    if (disposing)
    {
        // Code to dispose the managed resources of the class
    }
    // Code to dispose the un-managed resources of the class
 }

我知道只要我的 class 有一个实现 System.IDisposable 的(私有)成员,我的 class 就应该实现 System.IDisposable。如果布尔值处理为真,则 Dispose(bool) 应调用私有成员的 Dispose()。

如果在完成过程中调用 Dispose 为什么会出现问题?那么,如果在 finalize 期间调用以下 Dispose,为什么会出现问题?

protected void Dispose(bool disposing)
{
    if (myDisposableObject != null)
    {
        myDisposableObject.Dispose();
        myDisposableObject = null;
    }
 }

一般来说,您应该尽快摆脱资源。如果您不需要资源,为什么要保留它以浪费内存?

此外,为了在终结期间调用 Dispose(),您必须为您的对象创建终结器,即 C# 中的析构函数。然而,调用对象的终结器的确切时间是不确定的,这意味着您的托管对象在那一刻可能不再存在/无法安全访问。即使是执行终结器的线程也是不确定的,这也可能导致难以预见的问题。

出于这些原因,应创建终结器以仅释放非托管资源。

很少有程序员了解 'fully' 终结的工作原理。例如,垃圾收集器在对象实例化期间识别出您的类型具有终结器,并将您的实例放入称为 finalizequeue 的特殊内部数据结构中。实际上,当您使用 sos.dll (windbg) 调试您的应用程序时,您可以使用命令 !finalizeQueue 来显示具有终结器并且在稍后的某个时间点尚未完成的对象。

当对象的终结器 运行s 时,以下情况之一将适用于它可能持有的几乎所有 IDisposable 对象:

  1. 它持有对另一个对象的唯一引用,并且另一个对象的终结器已经 运行,所以不需要对它做任何事情。

  2. 它持有对那个其他对象的唯一引用,并且那个其他对象的终结器被安排到 运行,即使它还没有,也不需要做任何事情它.

  3. 其他对象还在使用IDisposable对象,这种情况下终结器一定不能调用Dispose.

  4. 另一个对象的 Dispose 方法不能安全地 运行 来自终结器线程上下文(或者,更一般地说,除了创建对象的线程上下文之外的任何线程上下文), 在这种情况下终结器不能调用 Dispose.

即使在上述 none 应用的情况下,除了实现 IDisposable 的事实之外,知道的代码可能会了解很多关于其清理要求的代码,并且应该经常使用更详细的清理协议。