【问题标题】:dispose vs finalize how the object free the memory?dispose vs finalize 对象如何释放内存?
【发布时间】:2014-01-15 06:45:24
【问题描述】:

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

【问题讨论】:

  • Afaik,gc 负责 任何 托管资源。
  • 托管内存仅由垃圾收集器回收。没有其他机制。
  • anton-tykhyy:so dispose 机制总是针对非托管资源,当finalize是所有托管资源的GC内部机制时,什么时候手动使用finalize?
  • 嗯,最终是的,因为所有有趣的东西(文件、套接字、数据库)都是非托管的当一切正常并且代码中没有错误时,以一种确定的方式。最终机制是在对象没有被正确处理时释放仅非托管资源,通常是因为有人忘记了Dispose。当你有一种非托管资源,SafeHandles 等还不够时,你只需要编写自己的终结器。

标签: c# dispose unmanaged


【解决方案1】:

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

// 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

【讨论】:

  • 你的意思是什么你应该阻止你的应用程序的用户直接调用一个对象的Finalize方法,将其范围限制为受保护这是误导,因为System.Object有一个finalize已经被保护的方法!
  • 通过保护 Finalize 方法,您可以防止应用程序的用户直接调用对象的 Finalize 方法。
  • 我想知道您所说的Finalize 方法是什么意思? Is this 或 Dispose(bool)?
【解决方案2】:

作为一个类的实现者,如果你持有应该被释放的托管资源,你就可以实现 Dispose。如果持有原生资源,则同时实现 Dispose 和 Finalize,并且都调用释放原生资源的通用方法。

这在msdn Implementing Finalize and Dispose to Clean Up Unmanaged Resources中有很好的描述

【讨论】:

  • +1 用于 MSDN 链接。另请注意,非托管资源几乎总是由派生自SafeHandle 的专用对象更好地持有。只有在极其特殊的情况下才需要显式终结器。
【解决方案3】:

两者兼而有之。 Dispose 方法是释放资源的地方,当您使用完对象后,您可以在代码中显式调用 Dispose。 Finalize 本身不做任何工作,而只是调用 Dispose。如果您不自己在代码中调用 Dispose,那么垃圾收集器将在某个时候调用 Finalize 以释放对象持有的资源。

内存不被视为用于处置目的的资源。一旦一个对象被释放并且不再有对它的引用,那么垃圾收集器就可以释放它占用的内存。想想看。在窗体上调用 Close 会释放它,但窗体仍然存在,因此显然它占用的内存尚未释放。仅释放窗口句柄。

【讨论】:

    【解决方案4】:

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

    不一定,Dispose 本身就足够了,如果您确保调用 Dispose 肯定。如果不是,建议实现finalizer,在回收内存的时候被GC调用。(注:不可靠,也可能不调用!)。

    第二件事,如果我们处置一个对象,该对象会释放内存吗 以及仅在那一刻的非托管资源或该对象的 内存稍后会被垃圾回收器释放

    否,处理不会释放内存。一旦 GC 认为是时候回收了,它就会这样做。它是不确定的。请记住,Disposing 意味着只调用一些名为 Dispose 的方法,仅此而已。

    一旦我们完成了一个对象,它会释放该对象的内存吗? 确定的时间,或者我们等到垃圾收集器释放它 记忆。

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

    希望这会有所帮助。

    【讨论】:

      【解决方案5】:

      我们应该使用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:因为 finalization 是由 GC 调用的,这就是为什么 在不可预测的时刻,Dispose 中的每个错误/泄漏都会 如果您从~Wrapper 调用Dispose(false),浮动错误(并且更难检测)。恕我直言,您可能想要实现最终确定的唯一情况是您获得 非托管内存块:

        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

      【讨论】:

      • @Anton Tykhyy:谢谢!当然是保护的(如果类是密封的,则为私有),我只是打错了。
      猜你喜欢
      • 2023-03-24
      • 2014-12-30
      • 1970-01-01
      • 2013-09-01
      • 2023-03-12
      • 1970-01-01
      • 2010-10-30
      • 2016-11-27
      • 2019-10-01
      相关资源
      最近更新 更多