Welcome to the Garbage Collection article series. In this series I have been dealing with Garbage Collection in C#. If you are interested iin learning the nitty-gritty of Garbage Collection then I recommend you visit the following previous articles:
In today's article we will learn one very important concept of Garbage Collection called "Finalize dispose pattern". Let me start with my small personal experience. In our organization we (developer people, better to say poor developer people at least in my case) conduct telephonic technical sessions as a first round screening test when we need .NET developers.
Once there was a need people for senior (5+ experience) .NET Developers and as usual we were conducting interview sessions by telephone and I also was in that team. One of my favorite questions was what is the basic idea of "what is the finalize dispose pattern and how to implement it?".
And the result is that 95% of developers (with 5+ years of experience) have never implemented the finalize dispose pattern and those who have implemented it don't properly know the need for it. They implemented it because their bosses/managers told then to. A few of them said they always use GC.Collect() in each page of an application when the page is closed. Hmm, what an idea? Collect garbage in each page unload event.
OK, I hope that after reading this article you will learn why the finalize dispose pattern is really needed and what its advantage is.
Why the finalize dispose is needed when the garbage collector automatically manages memory
Yes, this is one big question. Now think about the garbage collector. When is it run? If there is a shortage of memory for an application and more memory is needed. Now if we destroy an object that was created by ourself then the chances of the Garbage Collection executing will be very low.
And that's why we will learn the mechanism to destroy our own object after its operation uses the finalize dispose pattern.
What is Finalyze dispose?
It is nothing but a pattern or mechanism to clear the object from memory when we finish an operation associated with that specific object.
Before going into the explanation of the finalize dispose pattern I would like to discuss a little about the IDosposable interface. This interface needs to be implemented in a class where we want to implement the finalize dispose pattern.
IDisposable interface
This is a very interesting interface; why? It contains only one method, Dispose(), and that method needs to be implemented in the class.
How to implement the IDisposable interface
It is very simple. (But the truth to be told, I struggled a bit in my first time implementation). In the following example we will create one class that will contain a few managed and unmanaged resources. And we will implement the Dispose() method and within Dispose () we will clear the resources. Have a look at the following code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace WindowsForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click_1(object sender, EventArgs e)
{
Garbage g = null;
for (int i = 0; i < 10000; i++)
{
g = new Garbage();
g.Dispose();
}
}
}
public class Garbage: IDisposable
{
public String name = String.Empty;
SqlConnection con = null;
public Garbage()
{
name = "Sourav Kayal";
con = new SqlConnection();
}
~Garbage()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//Free managed resource here
name = null;
}
//Free unmanaged resource here
con = null;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
How it executes
Let's think first about iteration within a for loop.
- In a for loop the first object for the Garbage class will be created using g =new Garbage() statement.
- The constructor of the Garbage() class will execute and will initialize two resources (one string and one connection object).
- Then within the Main() function the next line g.Dispose() will execute. Then the Dispose function with no argument will execute.
publicvoid Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
Here we are seeing it's calling again the overloaded version of another Dispose function() with the argument true.
- Then the following function will be executed:
protectedvirtual void Dispose(bool disposing)
{
if (disposing)
{
//Free managed resource here
name = null;
}
//Free unmanaged resource here
con = null;
}
With the if we clean/release managed resources and outside of the if condition we will clear unmanaged resources.
- Then control will return again in the "void Dispose()" function and will execute the following line:
GC.SuppressFinalize(this);
This ensures that the Finalize/Destructor will be suppressed and will not execute for this object.
I have profiled this program with the CLR profiler and here is the object by age graph.
Here, we are seeing that most objects are being created in generation 0 and it is a sign of a good practice.
When we need to implement a finalize dispose pattern.
It's not mandatory for a finalize dispose pattern to be implemented in all classes. Implement the finalize dispose pattern when the class is dealing with many unmanaged resources.