Dispose()用于清理托管资源?

31 浏览
0 Comments

Dispose()用于清理托管资源?

在我找到的这个回答中,\n

\n当在代码中使用Dispose/Finalize模式时,应该在Finalize方法中清理非托管资源,并在Dispose方法中清理托管资源。\n

\n后来我找到了这篇很好的文章,关于finalize和dispose,我对它们有了清晰的理解。文章中有以下代码(第3页),用来解释这些概念:\n

class Test : IDisposable
{
    private bool isDisposed = false;
    ~Test()
    {
       Dispose(false);
    }
    protected void Dispose(bool disposing)
    {
       if (disposing)
       {
          // 清理类的托管资源的代码
       }
       // 清理类的非托管资源的代码
       isDisposed = true;
    }
    public void Dispose()
    {
       Dispose(true);
       GC.SuppressFinalize(this);
    }
}

\n但在下面,出现了同样的注释(我在问题开头引用过)。\n

\nDispose/Finalize模式\n Microsoft建议在处理非托管资源时同时实现Dispose和Finalize。开发人员应该先调用Dispose方法,然后Finalize方法会运行,即使开发人员忘记显式调用Dispose方法,资源也会在对象被垃圾回收时释放。Francesco Balena在他的博客中写道:“只有在类型调用分配非托管资源(包括非托管内存)并返回必须最终释放资源的句柄时,才应该使用Dispose/Finalize模式。Dispose和Finalize都必须在完成自身成员的清理或终结后,通过调用它们的父对象的相应方法链接到其父对象。”\n 简而言之,在使用Dispose/Finalize模式的代码中,应该在Finalize方法中清理非托管资源,并在Dispose方法中清理托管资源。\n

\n现在我又感到困惑了。整篇文章和代码示例中都显示应该在Dispose()中释放非托管资源。那这个注释的相关性是什么?\n编辑:\n确认了这行代码:\n

\n简而言之,在使用Dispose/Finalize模式的代码中,应该在Finalize方法中清理非托管资源,并在Dispose方法中清理托管资源。\n

\n是错误的,我编辑了这个回答

0
0 Comments

在上述内容中,提到了如果一个类有资源需要进行确定性清理,但没有可以在finalizer中有用地清理的资源,那么该类应该实现IDisposable接口,但不应该重写Finalize方法或者有一个析构函数。如果一个类持有多个资源,并且至少有一个可以在finalizer中进行清理,那么每个可以在finalizer中进行清理的离散资源应该封装在自己的Finalizer/destructor-equipped对象中(可以在受保护的嵌套类中定义),并且包含这些资源的类应该持有对包装对象的引用。完成这些操作后,外部类将符合具有Dispose方法但没有finalizer/destructor的类的模式。

根据上述内容,问题的出现原因是当一个类有资源需要进行确定性清理,但没有可以在finalizer中有用地清理的资源时,需要实现IDisposable接口来进行资源清理。解决方法是实现IDisposable接口,但不重写Finalize方法或者有一个析构函数。如果一个类持有多个资源,并且至少有一个可以在finalizer中进行清理,那么应该将每个可以在finalizer中进行清理的离散资源封装在自己的Finalizer/destructor-equipped对象中,并且包含这些资源的类应该持有对包装对象的引用。这样做可以确保资源得到正确的清理,同时避免了finalizer的开销。

0
0 Comments

Dispose()用于清理托管资源,那么为什么需要使用Dispose()以及如何解决这个问题呢?

首先,如果你处理的是非托管资源,就需要同时实现Dispose()和Finalize()方法。Dispose()方法由开发人员调用,用于在他们认为资源不再需要时立即释放资源。如果他们忘记调用Dispose()方法,则框架会在自己的垃圾回收周期中调用Finalize()方法来释放资源。

其次,如果你的对象在内部使用了可释放对象,那么你需要实现Dispose()方法,如果你创建并保留了对任何实现了Dispose()方法的类型的对象的引用,并且你还没有释放这些资源。

最后,如果以上两种情况都不是,那就不需要做任何事情,不需要实现Finalize()方法和Dispose()方法。

一些经典的例子:

System.IO.FileStream对象管理文件的锁定/流句柄,所以它实现了Dispose()和Finalize()方法。如果开发人员调用了Dispose()方法,那么其他程序可以立即访问该文件。如果开发人员忘记调用Dispose()方法,那么框架会在自己的垃圾回收周期中调用Finalize()方法来关闭句柄。

System.Text.StringBuilder没有任何非托管资源,所以不需要实现Dispose()和Finalize()方法。

对于模式来说,实现Dispose()方法意味着调用该类内部组件的任何.NET对象的Dispose()方法。而实现Dispose()方法意味着关闭原始句柄和指针。

下面是一个示例代码:

class Test : IDisposable
{
  private bool isDisposed = false;
  ~Test()
  {
    Dispose(false);
  }
  protected void Dispose(bool disposing)
  {
    if (!isDisposed)
    {
      if (disposing)
      {
        // Code to dispose the managed resources of the class
        internalComponent1.Dispose();
        internalComponent2.Dispose();
      }
      // Code to dispose the un-managed resources of the class
      CloseHandle(handle);
      handle = IntPtr.Zero;   
      isDisposed = true;
    }
  }
  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
}

上述代码中,Dispose(bool disposing)方法用于根据disposing参数的值来释放托管资源和非托管资源。Dispose()方法用于调用Dispose(bool disposing)方法,并调用GC.SuppressFinalize(this)来阻止调用Finalize()方法。

总结一下,当处理非托管资源时,需要实现Dispose()和Finalize()方法。如果对象内部使用了可释放对象,则需要实现Dispose()方法。如果不涉及非托管资源和可释放对象,则不需要实现Dispose()和Finalize()方法。

0