Last time (http://blogs.msdn.com/andrewdownum/archive/2004/12/13/282135.aspx) I talked about the consumer side of the dispose pattern (i.e. how to correctly use an object which supports the IDisposable pattern to ensure that its non-memory resources are cleaned up promptly). This time, we get to talk about the producer (that is the definition of a disposable object itself).
Say that you are developing an object which will wrap an unmanaged resource (like a database connection, a file handle, a network socket or anything which has a greater significance than its memory space implies). In this case you need to ensure that this resource gets freed up when it is no longer in use. The simple way to do this is to provide a Dispose() method which frees the resources when called (either explicitly, or indirectly via the using statement)
public class DisposableObject : IDisposable
{
private bool disposed = false;
public void Dispose()
if (!disposed)
disposed = true;
CleanupNativeResources();
}
protected virtual void CleanupNativeResources()
{ /*Do some interesting work here*/ }
The class above implements the IDisposable interface and when disposed, it will call CleanupNativeResources(), a virtual method which is assumed to actually implement whatever cleanup logic is required (for example calling a Win32 API to close a file handle).
But what happens if the consumer of this object forgets to call dispose. Even after all the warning given that it is the consumer’s responsibility to call the Dispose() method, sometimes these objects never get properly disposed.
Enter Finalization.
Finalization is a process through which an object can be registered with the runtime to have a special finalize method which will be called at some point after it can be guaranteed that there are no longer any references to the object. As mentioned earlier, this could happen at any time after there are no references remaining to the object (this could be a long time if the Garbage Collector doesn’t detect any reason it needs to collect) but it makes for a good last chance to clean up these resources.
public class FinalizableObject : IDisposable
GC.SuppressFinalize(this);
~FinalizableObject()
{ Dispose(); }
This latest snipped adds a finalizer method (in C# this uses the syntax of a method ~%ClassName%() where you would replace %ClassName% with the actual name of the class you are defining a finalizer for). In this case the finalizer simply calls the dispose method (which is generally a good idea).
There is also a call inside of the dispose method to GC.SuppressFinalize(this);
which notifies the runtime that the object no longer requires finalization and can be collected normally. This avoids the performance hit incurred by having a finalizer if it is not needed.
Now we can write a class which can be disposed by a caller that no longer needs it, and which will be disposed by the runtime automatically at some later date if that doesn’t happen, but we would like to encourage the consumer to use dispose functionality and to notify them when they are not doing so.
We can do this in a very similar way to what Visual C++ does for memory leaks. We simply keep track of all of the objects which are finalized (i.e. weren’t properly disposed) and then log some kind of information for them.
Following is the pattern that I use:
#if DEBUG
private System.Diagnostics.StackTrace allocStack;
#endif //DEBUG
#if THREADSAFE
//Use an int here so that we can later use Interlocked.CompareExchange
private int disposed = DISPOSED_FALSE;
private const int DISPOSED_TRUE = 1;
private const int DISPOSED_FALSE = 0;
#else //!THREADSAFE
#endif //THREADSAFE
public bool Disposed
get
return DISPOSED_TRUE == disposed;
return disposed;
public FinalizableObject()
allocStack = new System.Diagnostics.StackTrace();
if(DISPOSED_FALSE == System.Threading.Interlocked.Exchange(ref disposed, DISPOSED_TRUE))
System.Diagnostics.Debug.Assert(false, "FinalizableObject was not disposed" + allocStack.ToString());
Dispose();
Notice that if the debug compilation flag is set I capture the stack trace when the object is allocated and then fire a debug assertion in the finalizer that complains about the object being finalized. The assert then has enough information to figure out where the object was allocated and why it wasn’t released.
This code also optionally supports threadsafe handling (so that dispose can be called concurrently by multiple threads.
Hope this snipped helps someone out there who is struggling with finalization.