What did you do with my resources?

Published 2009-08-06 on Farid Zakaria's Blog

function mypage_head() {
echo ' '."n";
}
add_action('wp_head', 'mypage_head');
?>

I spent a good chunk of my day today really trying to learn about .NET Garbage Collection because as I had found I was under a lot of misconceptions/misunderstandings of how it works.

Dispose()

I was mistaking this for something similar to a destructor which in C# is the finalize method. This method is defined for any class that inherits from the IDisposable Interface. Implementing the interface allows you to also declare the object with the “using” keyword.
The purpose of this method is to provide the programmer a chance to “clean up” the object properly before they are released especially if they have references to unmanaged code (Window handles etc..)

The part where I was thrown off and took a long time reading to understand and learn is that in most cases (pretty much all if done correctly) you still don’t need to call Dispose on the object.

For instance, say you have a managed object with an unmanaged member variable. If the Dispose design method is implemented properly there should be a Finalize method that is declared which calls Dispose () anyways.

But remember, C# doesn't support destructors. Don't let the identical syntax fool you.

The problems begin to creep up in doing this in a efficient way. Thankfully .NET provides all the functionality needed to properly do this. When a class implements a finalize method, the way in which it gets garbage collected is differently than other items (Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework).In short, it gets put on a different queue which can result in a large performance cost.

The following example from MSDN shows how to properly implement the Dispose pattern:


using System;
using System.ComponentModel;

// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.

public class DisposeExample
{
    // A base class that implements IDisposable.
    // By implementing IDisposable, you are announcing that 
    // instances of this type allocate scarce resources.
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource.
        private IntPtr handle;
        // Other managed resource this class uses.
        private Component component = new Component();
        // Track whether Dispose has been called.
        private bool disposed = false;

        // The class constructor.
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue 
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the 
        // runtime from inside the finalizer and you should not reference 
        // other objects. Only unmanaged resources can be disposed.
        private void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources.
                if(disposing)
                {
                // Dispose managed resources.
                component.Dispose();
                }
             
                // Call the appropriate methods to clean up 
                // unmanaged resources here.
                // If disposing is false, 
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;            
            }
            disposed = true;         
        }

        // Use interop to call the method necessary  
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# destructor syntax for finalization code.
        // This destructor will run only if the Dispose method 
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide destructors in types derived from this class.
        ~MyResource()      
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(false) is optimal in terms of
            // readability and maintainability.
            Dispose(false);
        }
    }
    public static void Main()
    {
        // Insert code here to create
        // and use the MyResource object.   
    }
}

You can see how using this proper dispose pattern, if Dispose() was called by the programmer the finalize method is suppressed removing the need to call it again which would essential attempt to clean up the resource twice and we reattain the lost performance.

So I am in the woods on when someone would have to or would actually want to call Dispose on an object considering the GC will eventually call it for me anyways and the following:

What doesn’t happen when you call Dispose():

  1. Calling Dispose does not prioritize the object for garbage collection. It simply unloads the object’s (unmanaged) resources from memory.
  2. Calling Dispose does not deallocate the object from memory. Only the GC does that when it performs a collection of the generation in which the object resides.
  3. The CLR does not insert or run any code not in Dispose. The behaviour of Dispose is defined by the developer.
  4. Dispose must be called explicitly by the application. It is never called by the runtime. The only exceptions are when using C#’s using statement (see ShawnFa’s article for a good explanation of what exactly goes on), and the foreach keyword in C# will result in Dispose being called on the Enumerator
  5. Dispose is NOT threadsafe. This means two threads can call Dispose on the same object at the same time. Like for any other synchronization-sensitive method, take steps to make sure this doesn’t happen. I’ll give an example of when this might happen in the next section.

The oddest aspect as well is that the object is still alive after a call to Dispose (can very well be alive for a long while if the GC is in fact not needed to be called) and can be continued to be used unless the class checks in every method isDisposed which they never do.

Who knew being a garbage could be so fascinating...