Tuesday, May 28, 2013

Finalize and Dispose - How it works

Initially I had some difficulty in understanding how finalize and Dispose method works and its relation with Garbage Collection in .NET. Now a days realized that many are having the same issue even though they have sound practical experience. Following implementation is a simple way to understand how it works.

First lets understand what is Finalize and Dispose methods and how it is correlated to each other.

As per MSDN Dispose Method
  • should only be used for objects which uses unmanaged resources like FileStream etc. 
  • should be implemented using IDisposable interface.
  • should release all the resources that it owns. It should also release all resources owned by its base types by calling its parent type's Dispose method. The parent type's Dispose method should release all resources that it owns and in turn call its parent type's Dispose method, propagating this pattern through the hierarchy of base types. To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.
  • should call GC.SupressFinalize method so that object should not land up in Finalization Queue in Garbage Collection. Why so?? because when you call Dispose method you have already released all the managed and unmanaged resources to collect using GC directly without putting through the Finalization process, else you will get NullReferenceException.
As per MSDN Finalize Method
  • is protected and therefore is accessible only through this class or through a derived class e.g. protected virtual void Finalize()
  • called automatically after object is not accessible or after shutdown of application domain unless it is exempted from it by using GC.SupressFinalize. It releases all unmanaged resources before destroying the object.
  • time and order of execution of Finalizers cannot be predicted or pre-determined that's why you'll hear that the nature of finalization is "non-deterministic".
  • Destructors are the C# mechanism for performing cleanup operations. Destructors provide appropriate safeguards, such as automatically calling the base type's Destructor. In C# code, Object.Finalize cannot be called or overridden. But in the VB.NET, Finalize method can be override because it does support Destructor method.
  • In practical scenario if you have implemented Dispose method then you should implement Finalize or Destructor. If any scenario call Dispose then it need not call the finalize else it will. Destructor internally converted into System.Object.Finalize during Garbage Collection process.
Following is a sample class which has Dispose method and Destructor. Let's understand how it works and when it is called, when you can visualize it understanding it will be easy.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DisposableFinalizeExample
{
    class TestClass : IDisposable
    {
        public String sData;
        public TestClass()
        {
            sData = "Test Test Test";
            Console.WriteLine("Call Constructor");
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
            Console.WriteLine("Call Dispose Method");
        }
        protected virtual void Dispose(bool bDispose)
        {
            if (bDispose)
            {
                ReleaseManagedResource();
            }
            ReleaseUnmanagedResource();
        }
        void ReleaseManagedResource()
        {
            Console.WriteLine("Release Manage Resource");
        }
        void ReleaseUnmanagedResource()
        {
            Console.WriteLine("Release Unmanage Resource");
        }
        ~TestClass()
        {
            Dispose(false);
            Console.WriteLine("Destructor called in Finalization");
            Console.ReadLine();
        }
    }
}

Now, here is a sample console implementation which has two sections
  • Section 1 - Efficient way to call Dispose method
  • Section 2 - Calling Destructor in Garbage Collection. In execution you will observe that after the Destructor is called Console application closes automatically even though there is Console.ReadLine() to pause execution.

namespace DisposableFinalizeExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Section 1 - calling Dispose method automatically using "using"
            using (TestClass xx = new TestClass())
            {
                Console.WriteLine("2nd call " + xx.sData);
            }
            Console.ReadLine();
            // Section 2 - Calling Destructor which internally converted in Finalize and callec in GC
            if (true)
            {
                TestClass xx = new TestClass();
                if (xx.sData == "Test Test Test")
                {
                    Console.WriteLine("2nd call " + xx.sData);
                }
            
            }
            Console.ReadLine();
        }
    }
}

Here is the console output
Call Constructor                                            
2nd call Test Test Test                                     
Release Manage Resource                                     
Release Unmanage Resource                                   
Call Dispose Method                                         
<<PRESS ENTER>>                                             
Call Constructor                                            
2nd call Test Test Test                                     
<<PRESS ENTER>>                                             
Release Unmanage Resource                                   
Destructor called in Finalization                           

No comments:

Post a Comment