Microsoft .Net Framework provides a garbage collector that runs in the background and releases the memory occupied by managed objects when they are not referenced anymore in your code. Though the garbage collector is adept at cleaning up the memory occupied by managed objects, it is not guaranteed that memory occupied by unmanaged objects would be cleaned up when the next GC cycle executes. If you have unmanaged resources in your application, you should ensure that you release such resources explicitly when you are done using them. In this article, I will highlight the best practices that you should follow to cleanup resources used in your application.
The GC uses generations to maintain and manage the relative lifetime of objects that are created in the memory. Objects that are created new are placed in generation 0. The basic assumption is that a newly created object may have a shorter life time while an object that is old, may have a longer life time. When objects residing in generation 0 are not reclaimed after a GC cycle, they are moved to generation 1. Similarly, if objects residing in generation 1 survive a GC cleanup, they are moved to generation 2. Note that the GC runs more frequently in the lower generations that in the higher ones. So, objects that reside in generation 0 would be cleaned up more frequently compared to objects that reside in generation 1. So, it is a better programming practice to ensure that you use more local objects that objects in the higher scope to avoid objects being moved to higher generations.
Note that when you have a destructor in your class the runtime treats it as a Finalize() method. As finalization is costly, you should only use destructors if needed - when you have some resources in your class that you would need to cleanup. When you have a finalizer in your class, objects of those classes are moved to the finalization queue. If the objects are reachable, they are moved to the "Freachable" queue. The GC reclaims the memory occupied by objects that are not reachable. Periodically, the GC checks if the objects that reside in the "Freachable" queue are reachable. If they are not reachable, memory occupied by those objects are reclaimed. So, it is evident that objects that reside in the "Freachable" queue would need more time to be cleaned up by the garbage collector. It is a bad practice to have empty destructors in your C# class as objects for such classes would be moved to the finalization queue and then to the "Freachable" queue if need be.
A finalizer is implicitly called when the memory occupied by the object is reclaimed. However, a finalizer is not guaranteed to be called by the GC - it may or may not be called at all. In essence, a finalizer works on a non-deterministic mode – the runtime doesn’t guarantee that a finalizer would be called at all. You can however force the finalizer to be called though it is not at all a good practice as there are performance penalties associated. Finalizers should always be protected and should always be used to cleanup managed resources only. You should never allocate memory inside finalizer, write code to implement thread safety or invoke virtual methods from within a finalizer.
The Dispose method on the other hand provides a "deterministic cleanup" approach towards resource cleanup in .Net. However, the Dispose method unlike the finalizer should be called explicitly. If you have a Dispose method defined in a class, you should ensure that it is called. So, Dispose method should be called explicitly by the client code. But what if you forget to call Dispose method exposed by a class that uses unmanaged resources? Clients of an instance of a class that implements the IDisposable interface should call the Dispose method explicitly. In this case, you need to call Dispose from within the finalizer. This automatic deterministic finalization strategy ensures that the unmanaged resources used in your code are cleaned up.
You should implement IDisposable on every type that has a finalizer. It is a recommended practice to implement both Dispose and Finalize when you have unmanaged resources in your class.
The following code snippet illustrates how you can implement the Dispose Finalize pattern in C#.
protected virtual void Dispose(bool disposing)
// write code to cleanup managed objects
// write code to cleanup unmanaged objects and resources
This parameterized Dispose method can be called automatically from the destructor as shown in the code snippet below.
disposed = true;
This article is published as part of the IDG Contributor Network. Want to Join?