Skip to main content

.Net Garbage Collection and Finalization Queue

Finalize is a special method that is automatically called by the garbage collector (GC) before the object is collected. This method is only called by the GC. Destructor in C# are automatically translated into Finalize. You can see the IL code using IDASM where you will see that destructor is renamed to finalize.

  1. public class A
  2. {
  3. ~A()
  4. {
  5. Console.WriteLine("Class A Destructor");
  6. //Clean up unmanaged resources here
  7. }
  8. }
The CLR translate the above C# destructor to like this:
  1. public override void Finalize()
  2. {
  3. try
  4. {
  5. Console.WriteLine("Class A Destructor");
  6. //Clean up unmanaged resources here
  7. }
  8. finally
  9. {
  10. base.Finalize();
  11. }
  12. }

Fundamental of Finalization

When a new object is created, the memory is allocated in the managed heap. If newly created object have a Finalize() method or a destructor then a pointer pointing to that object is put into the finalization queue. Basically, finalization queue is an internal data structure that is controlled and managed by the GC. Hence each pointer in finalization queue points to an object that have its Finalize method call before the memory is reclaimed.
In the below fig. the managed heap contains 10 objects and objects 2,3,5,6,and 10 also contains the Finalize method. Hence pointers to these objects were added to the finalization queue.
When the garbage collector starts go through the roots, it make a graph of all the objects reachable from the roots. The below fig. shows a heap with allocated objects. In this heap the application roots directly refer to the objects 1,3,4,6 and object 3 & 6 refers to the objects 8 & 10. Hence all these objects will become the part of the live objects graph.
The objects which are not reachable from application's roots, are considered as garbage since these are not accessible by the application. In above heap objects 2,5,7,9 will be considered as dead objects.
Before the collections for dead objects, the garbage collector looks into the finalization queue for pointers identifies these objects. If the pointer found, then the pointer is flushed from the finalization queue and append to the freachable queue .The freachable queue is also an internal data structure and controlled by the garbage collector. Now each and every pointer with in the freachable queue will identify an object that is ready to have its Finalize method called.
After the collection, the managed heap looks like below Fig. Here, you see that the memory occupied by objects 7 and 9 has been reclaimed because these objects did not have a Finalize method. However, the memory occupied by objects 2 and 5 could not be reclaimed because their Finalize method has not been called yet.
When an object's pointer entry move from the finalization queue to the freachable queue, the object is not considered garbage and its memory is not reclaimed. There is a special run-time thread that is dedicated for calling Finalize methods. When there is no entry in the freachable queue then this thread sleeps. But when there is entry in the freachable queue, this thread wakes and removes each entry from the queue by calling each object's Finalize method.
The next time the garbage collector is invoked, it sees that the finalized objects are truly garbage, since the application's roots don't point to it and the freachable queue no longer points to it. Now the memory for the object is simply reclaimed.

Note

  1. The two GCs are required to reclaim memory used by objects that have Finalize method.

Comments

Popular posts from this blog

gcAllowVeryLargeObjects Element

There are numerous new features coming with .NET 4.5 and here, on this blog, you can find several posts about it. But the feature we are goint to talk about today is very exciting, because we were waiting for it more than 10 years. Since .NET 1.0 the memory limit of .NET object is 2GB. This means you cannot for example create array which contains elements with more than 2GB in total. If try to create such array, you will get the OutOfMemoryException. Let’s see an example how to produce OutOfMemoryException. Before that Open Visual Studio 2012, and create C# Console Application, like picture below. First lets create simple struct with two double members like example below: 1 2 3 4 5 6 7 8 9 10 11 12 public struct ComplexNumber {      public double Re;      public double Im;      public ComplexNumber( double re, double im)      {    ...

Support for debugging lambda expressions with Visual Studio 2015

Anyone who uses LINQ (or lambdas in general) and the debugger will quickly discover the dreaded message “Expression cannot contain lambda expressions”. Lack of lambda support has been a limitation of the Visual Studio Debugger ever since Lambdas were added to C# and Visual Basic.  With visual studio 2015 Microsoft has added support for debugging lambda expressions. Let’s first look at an example, and then I’ll walk you through current limitations. Example To try this yourself, create a new C# Console app with this code: using System.Diagnostics; using System.Linq; class Program { static void Main() { float[] values = Enumerable.Range(0, 100).Select(i => (float)i / 10).ToArray(); Debugger.Break(); } } Then compile, start debugging, and add “values.Where(v => (int)v == 3).ToArray()” in the Watch window. You’ll be happy to see the same as what the screenshot above shows you. I am using Visual Studio 2015 Preview and it has some limitati...

How to allow a very large object in .net application?

Since .NET 1.0 the memory limit of .NET object is 2GB. This means you cannot for example create array which contains elements with more than 2GB in total. If try to create such array, you will get the OutOfMemoryException. Let’s see an example how to produce OutOfMemoryException. Before that Open Visual Studio, and create C# Console Application. Lets create simple struct with two double members like example below: public struct ComplexNumber { public double Re; public double Im; public ComplexNumber(double re, double im) { Re = re; Im = im; } } As we know this structure consumes about 16 bytes of memory. So if we want to create array of this type which consume more than 2GB we need to create array at least with 134217728 instances. So this sample program below creates 130000000 (about 1,97 GB) of array. int maxCount = 130000000; ComplexNumber[] arr = null; try { arr = new ComplexNumber[maxCount]; } catch (Exception ex) { Console.WriteLine(ex.Message); } So if we run t...