Search code examples
c#memory-managementmemory-leaksgarbage-collectionfinalizer

How finalizer increases the life of an object in C#?


I am reading a book on C# memory management which says:

What’s important to understand is that a finalizer increases the life of an object. Because the finalization code also has to run, the .NET Framework keeps a reference to the object in a special finalization queue. An additional thread runs all the finalizers at a time deemed appropriate based on the execution context. This delays garbage collection for types that have a finalizer.

As per my knowledge finalizer would run on garbage collection only, not before it. So, how can it delay its garbage collection?


Solution

  • After going through MSDN links posted by comments and deleted answers, below are the details of the whole process:

    When a finalizable object is discovered (by GC) to be dead, its finalizer is put in a queue so that its cleanup actions are executed, but the object itself is promoted to the next generation. Therefore, you have to wait until the next garbage collection that occurs on that generation (which is not necessarily the next garbage collection) to determine whether the object has been reclaimed.

    Following is the code to demonstrate the same:

    using System;
    class Program
    {
        static void CreateDestructorReferences()
        {
            for (int i = 0; i < 1000; i++)
                _ = new Destructor();
        }
        static void CreateWithoutDestructorReferences()
        {
            for (int i = 0; i < 1000; i++)
                _ = new WithoutDestructor();
        }
        static void Main(string[] args)
        {
            CreateDestructorReferences();
            DemoGCProcess("****Objects With Destructors*****");
            CreateWithoutDestructorReferences();
            DemoGCProcess("****Objects Without Destructors*****");
            Console.ReadLine();
        }
    
        private static void DemoGCProcess(string text)
        {
            Console.WriteLine(text);
            var memory = GC.GetTotalMemory(false);
            GC.Collect(0);
            GC.WaitForPendingFinalizers();
            var memory1 = GC.GetTotalMemory(false);
            Console.WriteLine("Memory freed on first Garbage Collection on Generation 0:" + (memory - memory1));
            GC.Collect(1);
            var memory2 = GC.GetTotalMemory(false);
            Console.WriteLine("Memory freed on second Garbage Collection on Generation 0 and Generation 1:" + (memory1 - memory2));
        }
    }
    class Destructor
    {
    
        ~Destructor()
        {
            //Console.WriteLine("Destructor is called");
        }
    }
    class WithoutDestructor
    {
    
    }
    

    And here is the output of the above program: enter image description here