0

I have this small program (the real program is of course very different).

using System;

namespace Finalizer
{
    public class Simple
    {
        public Simple()
        {
            Console.WriteLine("Constructor");
        }
        ~Simple()
        {
            Console.WriteLine("Finalizer");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            var s = new Simple();
            s = null;
            GC.Collect();
            Console.WriteLine("Collected");
            Console.ReadKey();
        }
    }
}

And this is the output:

Hello World!
Constructor
Collected

I don't get why I don't see the Finalizer line.

Anyone?

Peter Poulsen
  • 440
  • 4
  • 11
  • 3
    GC is non-determinstic. If your app isn't requesting any more memory, most likely the GC is sat there thinking "your move". It has multiple heuristics built in, but the main ones are demand based – Marc Gravell Feb 14 '21 at 10:14
  • Also note that `s` is likely still on the stack. try `void local() { var s = new Simple(); } local();` – TheGeneral Feb 14 '21 at 10:24
  • What version of the framework are you using? I see "Finalizer" in the output when I try it. – Matthew Watson Feb 14 '21 at 10:29
  • Are you running debug or release build? – mjwills Feb 14 '21 at 10:37
  • 1
    I would make a minor point, which is that in real world applications the need for finalizers is _incredibly_ rare (I have never written one in almost 20 years of C# dev). Why do you think you need one? – mjwills Feb 14 '21 at 10:38
  • Notes: (1) The finalizer *is* called for a .Net Framework build. (2) If you put the creation of `Simple` into a separate method that you call from `Main()`, the finalizer will be called for .Net Framework *and* .Net Core. – Matthew Watson Feb 14 '21 at 10:43
  • @MatthewWatson Even if that is true today, it isn't _promised_. – mjwills Feb 14 '21 at 10:56
  • In .Net Core, if you want to be sure that the finalizer of an object is called before the app closes, declare it as a Filed (`private static Simple simple = new Simple();`). When you set it to `null` and call `GC.Collect()`, the finalizer is run immediately. In .Net Framework it's called anyway. – Jimi Feb 14 '21 at 10:56
  • 1
    @Jimi That is not promised. It might do that, it might not (since it isn't contractually obliged to). – mjwills Feb 14 '21 at 11:01
  • @00110001 - The GC is free to collect objects after their last reference in a method. It doesn't matter if it is on the stack or not. – Enigmativity Feb 14 '21 at 11:05
  • @mjwills It's true that there's no guarantee that the Finalizer is called every time you think it should, but in the context of this question, the static object's destructor is called. – Jimi Feb 14 '21 at 11:12
  • Try `GC.Collect(2); GC.WaitForPendingFinalizers(); GC.Collect(2);` from **outside** the function that creates and drops the object. And try in Release build. – Charlieface Feb 14 '21 at 11:34
  • 1
    @mjwills Indeed, it certainly isn't promised for .Net Core (and not guaranteed for .Net Framework), but I just wanted to draw attention to the difference in behaviour between .Net Framework and .Net Core. This difference is actually [documented here](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/destructors): `In .NET Framework applications (but not in .NET Core applications), finalizers are also called when the program exits.` – Matthew Watson Feb 14 '21 at 16:40
  • @mjwills [CriticalFinalizerObject](https://referencesource.microsoft.com/#mscorlib/system/runtime/reliability/criticalfinalizerobject.cs,13) – Jimi Feb 16 '21 at 12:20
  • @Jimi Normal developers shouldn't be writing finalizers. They _definitely_ shouldn't be inheriting from that class. ;) – mjwills Feb 16 '21 at 21:37
  • @mjwills What is a *normal developer*? Do you mean the .Net Team guys are *abnormal*? :) That class (and others) are part of the Framework. You probably mean *shouldn't be writing finalizers* when making use .Net objects (no need for a destructor here). You have to write finalizers sometimes. It's not exactly an exceptional task. Probably much less common in a *managed environment*, still a requirement in specific conditions. -- But, as in that case, finalizers can be guaranteed to run. As when you have a static Field object and you want your finalizer to execute in a specific case (planned). – Jimi Feb 16 '21 at 21:57
  • @Jimi I think it is fair to assume I am excluding developers of the framework _itself_, as I am sure you are fully aware. `You have to write finalizers sometimes.` Sometimes yes. But _very_ rarely. http://joeduffyblog.com/2005/12/27/never-write-a-finalizer-again-well-almost-never/ But you know this - you are arguing for the sake of arguing. ;) – mjwills Feb 16 '21 at 22:05
  • @mjwills Not *arguing*, really, just *poking* you (and/or the OP, they might be interested). Some *opinions* are more interesting that others. Btw, I know of that article, I also know what Stephen Toub has to say about finalizers; e.g.: [The Dispose guidelines really should be updated to point developers in the right direction](https://github.com/dotnet/docs/issues/8463). This is an interesting discussion, also because it has affected the MSDN Docs, which now reflect the conclusions of these arguments. I agree that Critical Finalizers are a different breed. – Jimi Feb 16 '21 at 22:18

0 Answers0