3

Why is my finalizer not being called?

using System;

class Program
{
    static void Main(string[] args)
    {
        Test test = new Test();
    }
}

class Test
{
    public Test()
    {
        Console.WriteLine("Start");
    }   

    ~Test()
    {
        Console.WriteLine("End");
    }
}

I searched on the Internet, I did not find anything suitable. I was expecting a console output "End" at the end.

O. Jones
  • 103,626
  • 17
  • 118
  • 172
  • I just tested your code and it worked exactly as expected. Maybe debug properly and place a breakpoint on the finalizer and see whether it gets hit. Actually, that was in a .NET 4.8.1 project. I just tried again in a .NET 6 project and the breakpoint wasn't hit. I guess it's because it's such a simple project and the whole app domain is presumably unloaded. If it was a longer-lived, more complex project then you'd probably find that it was hit at some stage, as the GC would clean up at some point. – jmcilhinney Jul 05 '23 at 10:02
  • Ok, thanks. I will take it into account – Pozetivchil Jul 05 '23 at 10:10
  • In the legacy version of the CLR, the finalizer thread got an extra 2 seconds to ensure that objects were finalized. That happened at appdomain unload, in this code right after Main() completes. CoreCLR no longer supports appdomains, when that support was removed we also lost that extra 2 seconds. I see no attempt at bringing that feature back, bit of a bug. – Hans Passant Jul 05 '23 at 10:53

3 Answers3

8

There's no requirement for all finalizers to be executed when the process terminates. Finalizers should not be used for things that absolutely must happen.

You can call GC.WaitForPendingFinalizers() if you really want to - along with other GC. methods to prompt garbage collection in the first place - but doing so in production code is usually a sign of a problematic design. Finalizers just aren't designed to work this way. They should be extremely rare in C# code in general; in my experience they're usually used to log warnings of "You appear not to have disposed of this, and you really should do - clean up will happen eventually, but this is something that should be cleaned up more eagerly."

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
4

I would recommend to read the "Everything you know is wrong" articles by Eric Lippert (Part One, Part Two). In short finalizers are tied to the GC and it is not guaranteed that finalizer will ever be called.

Another issue is covered in this answer - even if you will force the GC it still may not result in finalizer being called due to JIT possibly prolonging the lifetime of the object (i.e. it is not collected).

The general rule of thumb - do not use finalizers (implement if needed so they can be "last resort" if developer will do something incorrectly) and for deterministic resource clean up use the IDisposable pattern.

Read more:

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
4

Finalier can be called, but not necessary will be called: if Garbage collector doesn't collect Test instance, then finalizer will not be called. In case you want to guarantee the call (e.g. if you want to free some resources), you should implement IDisposable interface:

https://learn.microsoft.com/en-us/dotnet/api/system.idisposable?view=net-7.0

using System;

class Program
{
    static void Main(string[] args)
    {
        // Note "using"
        using Test test = new Test();
    }
}

// Note IDisposable and abscence of finalizer 
class Test : IDisposable
{
    public Test()
    {
        Console.WriteLine("Start");
    }   

    protected virtual void Dispose(bool disposing) 
    {
        Console.WriteLine("End");
    }

    public Dispose() {
        Dispose(true);
    }
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215