Question

I want to know should we use dispose and finalize if we are to deal with an object that is holding an unmanaged resource. second thing if we dispose an object does that object release memory along with the unmanaged resource on that moment only or that object's memory will be released by garbage collector later. same thing i want to know in fianilize context, once we finalize an object does that release memory for that object on the definite time or we have wait until garbage collector frees it's memory.

Était-ce utile?

La solution

You should prevent users of your application from calling an object's Finalize method directly by limiting its scope to protected. In addition, you are strongly discouraged from calling a Finalize method for a class other than your base class directly from your application's code. To properly dispose of unmanaged resources, it is recommended that you implement a public Dispose or Close method that executes the necessary cleanup code for the object. The IDisposable interface provides the Dispose method for resource classes that implement the interface. Because it is public, users of your application can call the Dispose method directly to free memory used by unmanaged resources. When you properly implement a Dispose method, the Finalize method becomes a safeguard to clean up resources in the event that the Dispose method is not called.

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

Source: MSND

Autres conseils

As the implementer of a class, if you hold managed resources that ought to be disposed, you implement Dispose. If you hold native resources, you implement both Dispose and Finalize, and both call a common method that releases the native resources.

This is very well described in msdn Implementing Finalize and Dispose to Clean Up Unmanaged Resources

Both. The Dispose method is where resources are released and it's Dispose that you call explicitly in code when you're done with an object. Finalize doesn't do any work itself but rather just calls Dispose. If you don;t call Dispose yourself in your code then the garbage collector will call Finalize at some point in order to release the resources held by the object.

Memory is not considered to be a resource for the purposes of disposal. Once an object has been disposed and there are no more references to it, then the garbage collector can free the memory it occupies. Think about it. Calling Close on a form disposes it but the form still exists, so obviously the memory it occupies has not been released. Only the window handle is released.

I want to know should we use dispose and finalize if we are to deal with an object that is holding an unmanaged resource

Not necessarily, Dispose itself enough if you will make sure you call Dispose for sure. If not it is recommended to implement finalizer which is called by GC at the time of reclaiming memory.(Note: It is not reliable, meaning it may not be called also!).

second thing if we dispose an object does that object release memory along with the unmanaged resource on that moment only or that object's memory will be released by garbage collector later

No, disposing won't release memory. GC will do that once it sees it is time to reclaim. It is in-deterministic. Keep in mind Disposing means just calling some method named Dispose that's it, nothing else.

once we finalize an object does that release memory for that object on the definite time or we have wait until garbage collector frees it's memory.

Hypothetical question, It is expected that immediately after Finalizer called object will be released from memory, but Eric says A destructor can "resurrect" an object, making a dead object alive again. That's really weird. Don't do it. So I think hard to answer this question.

Hope this helps.

We should use Dispose whenever we operate with unmanaged resources, the typical scheme is

  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);
    }
  }

Do not use finalize: since finalization is called by GC and that's why in unpredictable moments of time each error/leak in Dispose will be floating error (and harder to detect) if you call Dispose(false) from ~Wrapper. The only, IMHO, case when you may want to implement finalization is when you acquire unmanaged memory chunk:

  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);
    }
  }

For typical resources wrappers the best way is to use special classes like

 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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top