Very often, I come across IT professionals who ask the same question again and again - how to effectively manage resources in .Net applications. All are very well aware of the .Net Garbage Collection mechanism. However, very few have heard or implemented the "Disposable Pattern" for managing memory.
.Net effectively manages memory for you. You do not need to worry about the Memory Leaks of yesteryears with .Net. This is accomplished by the .Net Garbage Collection mechanism. The Garbage Collector (GC) keeps a watch at the Memory heap for objects and once space is full, and more space is needed for new objects, the GC will jump into action. Its primary work is to go thru all the objects to find objects that can be removed form memory. We can have a deep discussion about how it works (reference-tracing) in detail, at a later time. For now, all you need to understand is that the GC will remove unrequired/unused objects from memory.
However, one thing to keep in mind is that GC will remove only "managed/.Net" objects from memory. Yes you are correct, the Memory Leaks of yesteryears have not been fully eliminated. The main reason is the use of "unmanaged/non.Net" objects. GC will not release the non .Net resources. It is here that we need to understand the Disposable Pattern. Remember, setting an object to null (C#) or Nothing (VB.Net) does not actually release the resources associated with the object in .Net.
I have been trying to get some good information about Disposable Pattern for my C# project. Scouting the Internet for this information is difficult due to the few sites which provide details about this pattern.
The pattern involves implementing the IDisposable interface's Dispose() method along with the class destructor. The class destructor is automatically called by the GC when it tries to finalize objects to be released. Users cannot call the destructor directly. On the other hand, the Dispose() method is not called by GC but can be called by the users. In the Disposable Pattern, we need to release all resources used by our class in both these methods. Why from both?- you may ask.
The answer is simple: typically, when a class is no longer needed, it is always advisable to release, immediately, all resources associated with that object. The user has control of when to release objects only when the class implements IDisposable interface's Dispose method. So, if this method is implemented, users using this class can then call the Dispose() method once they know that they no longer need this class object. On the other hand, if the user fails to call the Dispose() method, the GC will kick in to call the finalize destructor in any case. So, even if the user fails to release memory once the object is no longer required, we are still safe as GC will do the work, albeit later. Hence both.
The following code snippet shows how the Disposable Pattern is implemented in C#.
1: using System;
2:
3: namespace DisposablePatternNamespace
4: { 5: class DisposablePatternClass : IDisposable
6: { 7: Boolean HasBeenDisposed = false;
8:
9: DisposablePatternClass()
10: { 11: //Constructor - Do what you want here;
12: }
13:
14: #region "Disposable Pattern Specific"
15: ~DisposablePatternClass()
16: { 17: //Destructor
18: //No need to change this code
19: //This is where you will implement Finalize code
20: ReleaseResources(false);
21: }
22:
23: //Dispose method to be called by user.
24: public void Dispose()
25: { 26: //No need to change this code
27: ReleaseResources(true);
28: //After call to ReleaseResources, no need for finalize.
29: GC.SuppressFinalize(this);
30: }
31:
32: void ReleaseResources(Boolean IsCalledFromDispose)
33: { 34: //Try to release resources only if they have not been previously released.
35: if (HasBeenDisposed == false)
36: { 37: if (IsCalledFromDispose == true)
38: { 39: //TODO: Code to release managed resources
40: //GC will automatically release Managed resources calling Destructor,
41: //but Dispose() will not.
42: }
43: //TODO: Code to release unmanaged resources
44: //TODO: set large fields to null
45: }
46: HasBeenDisposed = true;
47: }
48: #endregion
49: }
50: }
One may ask why to release Managed Resources as they will be released by GC automatically. A valid question. However, we must keep in mind one thing, if the managed component which we are using in our code, has a Dispose() method, the developer of that component must have placed it there for particularly releasing resources. The component developer is well aware of the resources which are used and needs to be released. Hence, it is always a very good idea to call the Dispose() method of objects we use, if they exist.
You can port the code to VB.Net very easily by just changing the destructor to Protected Overrides Sub Finalize().
I have created Visual Studio Item Templates for use with VS 2005 and 2008 for both VB.Net and C# for this pattern. Feel free to download the same and use it in your projects.
Download Item Templates for Visual Studio
Once downloaded, copy them to the following folder
(C# Item Template ZIP file in C# folder and VB ZIP file in VB folder)
Windows Vista:
C:\Users\UserID\Documents\Visual Studio 2008\Templates\ItemTemplates\Visual C#
C:\Users\UserID\Documents\Visual Studio 2008\Templates\ItemTemplates\Visual Basic
Windows XP:
C:\Documents and Settings\UserID\My Documents\Visual Studio 2008\Templates\ItemTemplates\Visual C#
C:\Documents and Settings\UserID\My Documents\Visual Studio 2008\Templates\ItemTemplates\Visual Basic
The folder location is same for Visual Studio 2005, except that the Visual Studio folder is named "Visual Studio 2005".
For more information on this topic, do refer to Microsoft MSDN site http://msdn2.microsoft.com/en-us/library/fs2xkftw.aspx