Tuesday, March 31, 2009

Dispose and Finalize in C#

When the .NET framework instantiates an object, it allocates memory for that object on the managed heap. The object remains on the heap until it's no longer referenced by any active code, at which point the memory it's using is "garbage," ready for memory deallocation by the .NET Garbage Collector (GC). Before the GC deallocates the memory, the framework calls the object's Finalize() method, but developers are responsible for calling the Dispose() method.

The two methods are not equivalent. Even though both methods perform object cleanup

The .NET garbage collector manages the memory of managed objects (native .NET objects) but it does not manage, nor is it directly able to clean up unmanaged resources. Managed resources are those that are cleaned up implicitly by the garbage collector. You do not have to write code to release such resources explicitly. In contrast, you must clean up unmanaged resources (file handles, database collections, etc.) explicitly in your code.

There are situations when you might need to allocate memory for unmanaged resources from managed code. As an example, suppose you have to open a database connection from within a class. The database connection instance is an unmanaged resource encapsulated within this class and should be released as soon as you are done with it. In such cases, you'll need to free the memory occupied by the unmanaged resources explicitly, because the GC doesn't free them implicitly.

Briefly, the GC works as shown below:

* It searches for managed objects that are referenced in managed code.
* It then attempts to finalize those objects that are not referenced in the code.
* Lastly, it frees the unreferenced objects and reclaims the memory occupied by them.

The GC maintains lists of managed objects arranged in "generations." A generation is a measure of the relative lifetime of the objects in memory. The generation number indicates to which generation an object belongs. Recently created objects are stored in lower generations compared to those created earlier in the application's life cycle. Longer-lived objects get promoted to higher generations. Because applications tend to create many short-lived objects compared to relatively few long-lived objects, the GC runs much more frequently to clean up objects in the lower generations than in the higher ones.

Finalizers—Implicit Resource Cleanup
Finalization is the process by which the GC allows objects to clean up any unmanaged resources that they're holding, before the actually destroying the instance. An implementation of the Finalize method is called a "finalizer." Finalizers should free only external resources held directly by the object itself. The GC attempts to call finalizers on objects when it finds that the object is no longer in use—when no other object is holding a valid reference to it. In other words, finalizers are methods that the GC calls on "seemingly dead objects" before it reclaims memory for that object.

Note that you cannot call or override the Finalize method. It is generated implicitly if you have a destructor for the class. This is shown in the following piece of C# code:—

   class Test
{

// Some Code

~Test
{
//Necessary cleanup code
}
}


The Dispose Method—Explicit Resource Cleanup
Unlike Finalize, developers should call Dispose explicitly to free unmanaged r
esources. In fact, you should call the Dispose method explicitly on any object
that implements it
to free any unmanaged resources for which the object may be
holding references. The Dispose method generally doesn't free managed
memory—typically, it's used for early reclamation of only the unmanaged
resources to which a class is holding references. In other words,
this method can release the unmanaged resources in a deterministic fashion.

However, Dispose doesn't remove the object
itself from memory. The object will be removed when the garbage
collector finds it convenient. It should be noted that the developer
implementing the Dispose method must call GC.SuppressFinalize(this)
to prevent the finalizer from running.

The following code illustrates how to implement the Dispose method on
a class that implements the IDisposable interface:



class Test : IDisposable
{
private bool isDisposed = false;

~Test()
{
Dispose(false);
}

protected void Dispose(bool disposing)
{
if (disposing)
{
// Code to dispose the managed resources of the class
}
// Code to dispose the un-managed resources of the class

isDisposed = true;
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}


The Dispose/Finalize Pattern
Microsoft recommends that you implement both Dispose and Finalize when working
with unmanaged resources. The correct sequence then would be for a
developer to call Dispose. The Finalize implementation would run and the
resources would still be released when the object is garbage collected
even if a developer neglected to call the Dispose method explicitly.

Simply put, cleanup the unmanaged resources in the Finalize method and the
managed ones in the Dispose method, when the Dispose/Finalize pattern has been
used in your code.

As an example, consider a class that holds a database connection instance.
A developer can call Dispose on an instance of this class to release the
memory resource held by the database connection object. After it is freed,
the Finalize method can be called when the class instance needs to be
released from the memory.

Reference: http://www.devx.com/dotnet/Article/33167

No comments: