dispose vs finalize对象如何释放内存?

时间:2014-01-15 06:45:24

标签: c# dispose unmanaged

我想知道,如果我们要处理持有非托管资源的对象,我们是否应该使用dispose和finalize。 第二件事,如果我们处理一个对象,那个对象只会在那个时刻释放内存以及非托管资源,或者该对象的内存将在稍后由垃圾收集器释放。我想在fianilize上下文中知道同样的事情,一旦我们确定一个对象确实在确定的时间释放该对象的内存,或者我们等到垃圾收集器释放它的内存。

5 个答案:

答案 0 :(得分:4)

您应该通过将其范围限制为受保护来阻止应用程序的用户直接调用对象的Finalize方法。此外,强烈建议您不要直接从应用程序的代码调用除基类之外的类的Finalize方法。为了正确处理非托管资源,建议您实现一个公共Dispose或Close方法,该方法为对象执行必要的清理代码。 IDisposable接口为实现接口的资源类提供Dispose方法。因为它是公共的,所以应用程序的用户可以直接调用Dispose方法来释放非托管资源使用的内存。正确实现Dispose方法后,如果未调用Dispose方法,Finalize方法将成为清理资源的安全措施。

// Design pattern for a base class.
public class Base: IDisposable
{
    private bool disposed = false;

    //Implement IDisposable.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Free other state (managed objects).
            }
            // Free your own state (unmanaged objects).
            // Set large fields to null.
            disposed = true;
        }
    }

    // Use C# destructor syntax for finalization code.
    ~Base()
    {
        // Simply call Dispose(false).
        Dispose (false);
    }
}

// Design pattern for a derived class.
public class Derived: Base
{
    private bool disposed = false;

    protected override void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Release managed resources.
            }
            // Release unmanaged resources.
            // Set large fields to null.
           // Call Dispose on your base class.
            disposed = true;
        }
        base.Dispose(disposing);
    }
    // The derived class does not have a Finalize method
    // or a Dispose method without parameters because it inherits
    // them from the base class.
}

来源:MSND

答案 1 :(得分:2)

作为类的实现者,如果您拥有应该处理的托管资源,则实现Dispose。如果您拥有本机资源,则实现Dispose和Finalize,并且都调用释放本机资源的公共方法。

这在msdn Implementing Finalize and Dispose to Clean Up Unmanaged Resources

中有详细描述

答案 2 :(得分:1)

两者。 Dispose方法是释放资源的位置,它是在完成对象时在代码中显式调用的Dispose。 Finalize本身不做任何工作,而只是调用Dispose。如果你没有;在你的代码中调用Dispose自己,那么垃圾收集器会在某个时候调用Finalize来释放对象所拥有的资源。

内存不被视为用于处置目的的资源。一旦一个对象被丢弃并且没有更多的引用,那么垃圾收集器就可以释放它占用的内存。想一想。在表单上调用Close处理它但表单仍然存在,所以显然它占用的内存还没有被释放。只释放窗口句柄。

答案 3 :(得分:1)

我们应该使用Dispose 每当我们使用非托管资源进行操作时,典型的方案是

  public class Wrapper: IDisposable {
    ...

    // Let's acquire resource in constructor
    public Wrapper(...) {
      ...
      AcquireResource(); 
      ...
    }

    public Boolean IsDisposed {
      get;
      protected set; // <- Or even "private set"
    }

    protected virtual Dispose(Boolean disposing) {
      if (IsDisposed) 
        return;   

      if (disposing) {
        ReleaseResource();
      }

      IsDisposed = true;
    }

    public Dispose() {
      Dispose(true);
      GC.SuppressFinalize(this);
    }
  }

不要使用finalize :因为GC会调用终结,这就是原因 在不可预测的时刻 Dispose中的每个错误/泄漏都将是 如果您从Dispose(false)致电~Wrapper,则浮动错误(以及难以检测)。当你想要实现最终化时,唯一的恕我直言,就是当你获得时 非托管内存块

  public class MemoryWrapper: IDisposable {
    private IntPtr m_Handle;
    private int m_Size;

    public void AcquireMemory(int size) {
      ...
      m_Size = size;
      m_Handle = UnmanagedAcquireMemory(size);
      // Let GC know that we acquire memory in some weird way
      GC.AddMemoryPressure(size);
    }

    private void ReleaseMemory() { 
      ...
      UnmanagedReleaseMemory(m_Handle, m_Size);
      // Let GC know that we release memory in some weird way
      GC.RemoveMemoryPressure(m_Size);
    }

    private MemoryWrapper(int size) {
      AcquireMemory(size);
    }

    public Boolean IsDisposed {
      get;
      protected set; // <- Or even "private set"
    }

    protected virtual Dispose(Boolean disposing) {
      if (IsDisposed) 
        return;   

      ReleaseMemory();

      IsDisposed = true;
    }

    public Dispose() {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    // Possible finalizer
    ~MemoryWrapper() {
      Dispose(false);
    }
  }

对于典型的资源包装器,最好的方法是使用像

这样的特殊类
 SafeHandle
 SafeHandleZeroOrMinusOneIsInvalid

http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k(System.Runtime.InteropServices.SafeHandle);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)&rd=true

答案 4 :(得分:1)

  

我想知道,如果我们要处理持有非托管资源的对象,我们是否应该使用dispose和finalize

不一定,Dispose本身就足够了,如果你确定你肯定会调用Dispose 。如果不是,建议实现在回收内存时由GC调用的finalizer。(注意:它不可靠,这意味着它也可能不被调用!)。

  

第二件事,如果我们处理一个对象就会释放该对象释放内存   以及那个时刻或该对象的非托管资源   内存将在以后由垃圾收集器发布

,处理不会释放内存。一旦它认为是时候回收,GC就会这样做。这是不确定的。请记住,Disposing意味着只调用一个名为Dispose的方法,就是它,没有别的。

  

一旦我们完成一个对象,就会释放该对象的内存   确定的时间或我们等到垃圾收集器释放它   存储器中。

假设性问题,预计在Finalizer被调用对象被释放后,会立即释放Eric says A destructor can "resurrect" an object, making a dead object alive again. That's really weird. Don't do it。所以我觉得很难回答这个问题。

希望这有帮助。