Garbage Collection - Dispose Vs Finalize And IDisposable Pattern

Introduction

 
In this article, we are going to see how Finalize, Destructor, IDisposable pattern, and Using block works in a C# application.
 
Lets have a small introduction to all of them.
 
Finalize - This is used to release the unmanaged resources.
 
The managed resources are like class created in C#, Vb.Net and any other class created under .net languages.
 
The cleanup and releasing of the unmanaged resources are done under finalize method.
 
If your class are not using unmanaged resources then forget about Finalize method. If your class is using unmanaged resources then implement finalize method.
 
We can not call the finalize method using the class object. The finalize method is called by garbage collector.
 
Garbage Collection - Dispose Vs Finalize And IDisposable Pattern
 
The first time when the object is created then it is going to sit in generation 0. The Garbage collector frequently checks the generation 0 whether if any object is inactive. It the object is inactive and no one is using the object then immediately it is going to release and deallocate the memory.
 
In the same way, garbage collector checks the object header and finds the object has implemented the finalize method then the garbage collector moves that object to finalize queue.
 
The checking of finalize queue is very less. Even if the object is inactive and object is not more in usage still it will be in memory heap and also we don’t know when it will release the unmanaged resources.
 
When the code is compiled then the destructor is converted to finalize. Whenever we use unmanaged resources then make sure to implement the destructor method.
 
Create a sample console project.
 
Add classes as below,
  1. namespace GarbageCollectorPorgram  
  2. {  
  3.     class ClassA  
  4.     {  
  5.         public ClassA()  
  6.         {  
  7.             Console.WriteLine("Created ClassA");  
  8.         }  
  9.         ~ClassA()  
  10.         {  
  11.             Console.WriteLine("Destructing -- ClassA");  
  12.         }  
  13.     }  
  14.   
  15.     class ClassB : ClassA  
  16.     {  
  17.         public ClassB()  
  18.         {  
  19.             Console.WriteLine("Creating ClassB");  
  20.         }  
  21.         ~ClassB()  
  22.         {  
  23.             Console.WriteLine("Destructing -- ClassB");  
  24.         }  
  25.     }  
  26.   
  27.     class ClassC : ClassB  
  28.     {  
  29.         public ClassC()  
  30.         {  
  31.             Console.WriteLine("Creating ClassC");  
  32.         }  
  33.         ~ClassC()  
  34.         {  
  35.             Console.WriteLine("Destructing -- ClassC");  
  36.         }  
  37.     }  
  38.   
  39.     class ClassD  
  40.     {  
  41.     }  
  42.   
  43. }  
Open program.cs:
  1. namespace GarbageCollectorPorgram  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             ClassC objC = new ClassC();  
  8.             Console.WriteLine("Object C is created..");  
  9.             objC = null;  
  10.             Console.WriteLine("Object C is assigned to null.. Object now destructing..");  
  11.             Console.ReadLine();  
  12.         }  
  13.     }  
  14. }  
Garbage Collection - Dispose Vs Finalize And IDisposable Pattern
 
You can see the finalize method, but where is the destructor method. This is getting converted to override finalize method. So, using the destructor we define the finalize method.
 
Let us see how the destructor is actually calling.
 
Run the application,
 
Garbage Collection - Dispose Vs Finalize And IDisposable Pattern
 
You can see the garbage collector didn’t call the finalize method of these classes.
 
Then when we close the exe then at that time it will call the finalize method of all the classes. Even if the object is inactive but it is still Garbage collector maintains the object’s memory.
 
Garbage Collection - Dispose Vs Finalize And IDisposable Pattern
  1. GC.Collect();  
Let’s see what GC.Collect() does.
 
The garbage collector’s Collect() method instructing the GC to clear off or deallocate all the inactive object’s memory. This is a very expensive operation and goes to all the generation (0,1,2) to clear off the memory or deallocate the objects in one shot.
 
In our program objC = null; we are doing nothing but making the object objC as inactive and the statement GC.Collect() goes on and immediately releases the objects.
 
Change the main method’s statements as below,
  1. ClassC objC = new ClassC();  
  2.             Console.WriteLine("Object C is created..");  
  3.             objC = null;  
  4.             GC.Collect();  
  5.             Console.WriteLine("Object C is assigned to null.. Object now destructing..");  
  6.             Console.ReadLine();  
Now run the application,
 
Garbage Collection - Dispose Vs Finalize And IDisposable Pattern
 
There is a performance issue when keeping the inactive objects memory for a long time and this is not the right technique to manage the memory,
 

IDisposable Interface

 
IDisposable has only one method that is Dispose method. We can use the dispose method for the same purpose to clean up the unmanaged resources. So when you are done with your object then simply call the dispose method.
 
Let us take an example that will implement the Dispose method of IDisposable interface.
 
Add the class as below,
  1. namespace GarbageCollectorPorgram  
  2. {  
  3.     public class DisposableTest : IDisposable  
  4.     {  
  5.         private bool isDisposed = false;  
  6.   
  7.         public void Print(string message)  
  8.         {  
  9.             Console.WriteLine("Hello " + message);  
  10.         }  
  11.   
  12.         ~DisposableTest()  
  13.         {  
  14.             Console.WriteLine("Destructor/Finalize of DisposableTest");  
  15.             Dispose(false);  
  16.         }  
  17.         public void Dispose()  
  18.         {  
  19.             Dispose(true);  
  20.             GC.SuppressFinalize(this);  
  21.         }  
  22.         protected void Dispose(bool dispose)  
  23.         {  
  24.             if (!isDisposed)  
  25.             {  
  26.                 if (dispose)  
  27.                 {  
  28.                     // to cleanup managed objects  
  29.                 }  
  30.                 // To cleanup unmanaged resources/objects  
  31.                 isDisposed = true;  
  32.             }  
  33.         }  
  34.     }  
  35. }  
Click on IDisposable and press f12,
 
Garbage Collection - Dispose Vs Finalize And IDisposable Pattern
 
You can see there is only one method Dispose.
 
If we are implementing the Dispose method then it means we have got the control of whenever you want to call the dispose method based on the right time according to you. So whoever is using the class has the responsibility to clear the unmanaged resources.
 
If you are depending on dispose method then there is a possibility that we forgot to call the dispose method then what will happen. Also, it may cause a memory leak.
 
So we have implemented the finalize as well as Dispose method. Now, if user forgot to call the dispose method then that time my finalize method will activate. Also if user calls the dispose method then I don’t want to call the finalize method to activate. So we have specified in Disipose method().
  1. public void Dispose()  
  2.         {  
  3.             Dispose(true);  
  4.             GC.SuppressFinalize(this);  
  5.         }  
Suppose user called the dispose method then internally we are specifying the GC to suppress the finalize for the particular 'this' object. That means it will take out from the finalize queue immediately, and Finalize method will not be triggered by the Garbage collector.
 
Also, we can use IDisposable for releasing the managed, unmanaged resources and components.
 
In our program, we have finalize method to release the unmanaged resources,
  1. ~DisposableTest()  
  2.         {  
  3.             Console.WriteLine("Destructor/Finalize of DisposableTest");  
  4.             Dispose(false);  
  5.         }  
We are passing false inside Dispose method.
  1. protected void Dispose(bool dispose) {  
  2.  if (!isDisposed) // will be true    
  3.  {  
  4.   if (dispose) {  
  5.    // to cleanup managed objects    
  6.   }  
  7.   // To cleanup unmanaged resources/objects    
  8.   isDisposed = true;  
  9.  }  
  10. }  
So, first step will be true and it will check another if(dispose) that will be false and this will only clean up the unmanaged resources and set the value idDisposed to true.
 
Open program.cs,
  1. namespace GarbageCollectorPorgram  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             DisposableTest obj = new DisposableTest();  
  8.             Console.WriteLine("DisposableTest object is created..");  
  9.             obj.Print("Good Morning..");  
  10.             obj = null;  
  11.             Console.WriteLine("Assigned null..  Object is destructing..");  
  12.             Console.ReadLine();  
  13.         }  
  14.     }  
  15. }  
Run the application,
 
Garbage Collection - Dispose Vs Finalize And IDisposable Pattern
 
The finalize method has not been called.
 
Press any key,
 
Garbage Collection - Dispose Vs Finalize And IDisposable Pattern
 
Then the finalize method is called.
 
So when we close the exe then garbage collector calls the finalize method. Even if you have implemented the IDisposable dispose method but you forgot to call the dispose method then it will call the finalize method.
 
Now let us call the dispose method,
 
Change the program.cs statements
  1. namespace GarbageCollectorPorgram  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             DisposableTest obj = new DisposableTest();  
  8.             Console.WriteLine("DisposableTest object is created..");  
  9.             obj.Print("Good Morning..");  
  10.             obj.Dispose();  
  11.             obj = null;  
  12.             Console.WriteLine("Assigned null..  Object is destructing..");  
  13.             Console.ReadLine();  
  14.         }  
  15.     }  
  16. }  
Run the application,
 
Garbage Collection - Dispose Vs Finalize And IDisposable Pattern
 
Now you will not see the Destructor/finalize of the object statement execution. It means the Dispose is going to taking care of releasing the unmanaged resources also suppress the finalize method.
 

Using block

 
Open program.cs and change the statements as below:
  1. namespace GarbageCollectorPorgram  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             using (DisposableTest obj = new DisposableTest())  
  8.             {  
  9.                 Console.WriteLine("DisposableTest object is created..");  
  10.                 obj.Print("Good Morning..");  
  11.             }  
  12.             Console.WriteLine("Assigned null..  Object is destructing..");  
  13.             Console.ReadLine();  
  14.         }  
  15.     }  
  16. }  
To avoid the calling of dispose method and to forget the calling of dispose method. Dot net has introduced a Usign block.
 
So if you are creating the object that has implemented the IDisposable interface then Using block will take care of calling the dispose method for the object. At the end of the block it will automatically call the Dispose method.
 
Run the application,
 
Garbage Collection - Dispose Vs Finalize And IDisposable Pattern
 
You can see the object didn’t call the finalize method.
 
So if any class has implemented the IDisposable interface then try using the Using block to create the instance.
 
Soo many classes like db connection class have implemented the Dispose method. So, if you are seeing the Dispose method has been implemented then try using the Using block to create the object.
 
EG - if you are creating the SqlConnection object/instance then try creating under Using block because SqlConnection implements the Dispose method that dispose method is used to release the DB Connection, and db Connection are unmanaged resources.
 
So the best practice is that if you are using the class/.net classes that has implemented the Dispose method then try to create object under Using block. If you are not using the Using block then make sure to call the dispose method explicitly. This practice will help to avoid the GC finalize queue, also to improve the performance.
 
Thankyou.


Similar Articles