Unmanaged resources are expensive. Therefore, you can't
afford to have managed objects that encapsulate unmanaged resources
lying dormant in memory waiting for the garbage collector to finalize
them. This article shows library developers how to provide an
interface to such objects so that they can be finalized at will.
In the Common Language Runtime (CLR), an object is
constructed using the newobj Common Intermediate Language (CIL)
instruction and destroyed by the garbage collector when all
references to it have been lost. Construction of an object involves
the allocation of memory and the initialization of the object state
(by calling the constructor). Destruction of an object involves the
tearing down of its state (by calling the finalizer) and freeing the
allocated memory.
The garbage collector is a dedicated low-priority thread that
runs periodically and destroys all unreferenced objects, but exactly
when the garbage collector will run is not known. This behavior is
called nondeterministic finalization.
A garbage collection can be explicitly invoked by using the
static System.GC.Collect method. However, this is not advisable
because garbage collection is an expensive operation, so it should be
left to the system to decide when to invoke it.
Now imagine an object that encapsulates some unmanaged
resource. From the time all references to this object are lost to the
time the garbage collector finalizes it, the unmanaged resource will
lie around unused. This unmanaged resource could be a database
connection, a file handle, a bitmap, or something else that is
critical in the context of the application. Ideally, such an object
should provide the interface to free up the encapsulated unmanaged
resource after it is no longer needed. This is what the Dispose
pattern does - it facilitates deterministic finalization.
The Dispose pattern allows library developers to provide
functionality to their classes to free up any encapsulated unmanaged
resources. The .NET Framework Base Class Library provides the
foundations for implementing the Dispose pattern through the
IDisposable interface.
The Dispose pattern is used extensively in the .NET Framework
base class library. Classes such as System.IO.TextReader,
System.Drawing.Bitmap, and System.Data.SqlClient.SqlConnection
implement the Dispose pattern. They do so because they encapsulate
unmanaged resources. For instance, the System.Data.SqlClient.
SqlConnection class encapsulates a database connection. If it did not
implement the Dispose pattern, there would be no way for developers
to close the connections after use. This would leave the connection
open until the garbage collector ran. Given the nondeterministic
behavior of the garbage collector, it is possible that at times the
connection pool will not have any more connections to serve.
The IDisposable Interface
The IDisposable interface is found in the System namespace.
It declares a single method, Dispose, which takes no parameters and
returns void.
public interface IDisposable
{
void Dispose ();
}
Implementing IDisposable
A class that encapsulates unmanaged resources can implement
IDisposable in the following manner:
Declare a private Boolean variable that tracks whether or not
the object has been disposed.
private bool disposed = false;
Implement a protected Dispose method that takes a Boolean
parameter. In this method, free up all unmanaged resources. If the
parameter passed is true, call Dispose on member fields that
encapsulate unmanaged resources. Set disposed to true to indicate if
the object has been disposed (see Listing 1).
Notice that the first if condition checks whether
or not the object has been disposed.
If the object has been disposed previously, the
method returns without doing anything. This way, Dispose can be
called on an object any number of times without any problem.
Implement the IDispose.Dispose method (the public Dispose).
In it, call the protected Dispose, passing it true. Since the object
has been disposed, call GC.SupressFinalize, passing this as the
parameter to prevent the finalizer from being called when the garbage
collector runs.
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
GC.SuppressFinalize prevents an object that has
been disposed from being finalized again by the garbage collector. It
also helps with optimization because finalization is an expensive
operation, as well as redundant in this case.
Implement the finalizer (using the C# destructor syntax) -
which overrides the Finalize method provided by Object. Call the
protected Dispose and pass it false.
~UnamangedResourceContainer ()
{
Dispose (false);
}
For all other methods and properties, check if disposed is
true. If yes, throw an ObjectDisposedException, otherwise continue
with the normal processing.
public void DoSomething ()
{
if (disposed)
throw ObjectDisposedException ();
// ...
}
Inheriting from a Class That Implements IDisposable
If your class is inheriting a class that already implements
IDisposable, all you need to do is override the protected Dispose
method, as shown in Listing 2 .
The finalizer and the public Dispose that are inherited from
the base class are not overridden.
Domain-Specific Disposing
The Dispose method needs to be provided by any class that
implements the IDisposable interface. However, in certain cases a
domain-specific method name may be more semantically appropriate. For
example, a class that abstracts operating system processes may need a
method called Kill instead of Dispose. In such a case we can
implement a public Kill method too. The Kill method calls the public
Dispose method.
public void Kill ()
{
Dispose ();
}
Conclusion
In this article we have seen that the management of system
resources is very important for the proper functioning of an
application. The CLR takes the error-prone task of memory management
away from the developer. Also, the System.Object class provides the
Finalize method for developers to override in their classes for other
resource cleanup routines. This method is called by the garbage
collector.
Since we don't know when the garbage collector will run,
chances are that idle resources will hang around in memory when they
could be used some other place in the application. To alleviate this
problem, the .NET Framework class library provides us with the
IDisposable interface, which when implemented provides a way to free
the unmanaged resources as soon as they are no longer needed.
I hope I was able to show you something useful in this
article. Happy programming!
Resources
MSDN TV: Resource Management with the CLR: The IDisposable Pattern: http://msdn.microsoft.com/msdntv/episode.aspx?
xml=episodes/en/20030501CLRBA/manifest.xml
Implementing Finalize and Dispose to Clean Up Unmanaged
Resources:
http://msdn.microsoft.com/library/en-us/cpgenref/
html/cpconfinalizedispose.asp
SIDEBAR
Tips & Tricks
Override System.Object.Finalize only if your class wraps some unmanaged resource.
Don't implement the dispose pattern if your class does not have a finalizer.
Don't forget to call System.GC.SuppressFinalize after an object is disposed.
When finalizing, don't call Dispose on any managed object
because it may have already been destroyed by the garbage collector.
About The Author
Mujtaba Syed is a software architect with Marlabs Inc. He is an MCSD in .NET (early achiever certificate) and an MCAD in .NET (charter member). He has six years of software
architecting and developing experience, half of which were focused on .NET.
mujtaba@marlabs.com
Listing 1
protected void Dispose (bool disposing)
{
if (!disposed)
{
if (disposing)
{
/*
Call dispose on all member fields which
encapsulate unmanaged resources...
*/
}
// Free up unmanaged resources...
disposed = true;
}
}
Listing 2
protected void Dispose (bool disposing)
{
if (!disposed)
{
if (disposing)
{
/*
Call dispose on all member fields which
encapsulate unmanaged resources...
*/
}
// Free up unmanaged resources...
base.Dispose (disposing);
disposed = true;
}
}
All Rights Reserved
Copyright © 2004 SYS-CON Media, Inc.
E-mail:
info@sys-con.com