Finalizer not called
Asked Answered
C

4

11

I have a class in C# where I want to close out some communication ports properly when my class is being disposed. However, the finalizer is never being called when I exit the program. Why is that? Am I doing something wrong?

I am calling the dispose manually which goes through and closes all communications. This is not fired either.

Here is the finalizer I am using:

~Power()
{
    Dispose(false);
}
Collyer answered 5/3, 2011 at 0:51 Comment(1)
I'm guessing that your problem is not where you think it is. It's hard to tell without seeing more of your program, though.Paulo
P
10

The finalizer (which is what you're using here) is only called during the Finalization phase, which will happen during GC.

If you implement IDisposable correctly, this should never get called. I cover this in detail on my series on IDisposable.

That being said, if your "communication ports" are handled via managed classes, you shouldn't use a finalizer at all. This is adding overhead that does not help you whatsoever. Just implement IDisposable (properly), and let the managed wrappers around the port classes handle finalization if required.

Pitterpatter answered 5/3, 2011 at 0:55 Comment(2)
How do I implement IDisposable 'properly'? My class inherits usercontrol. I thought that implemented IDisposable? Clearly I may be wrong on this.Collyer
@Spenduku: I'd recommend reading my articles linked above. I explain this in detail, including subclassing an IDisposable class. What class are you using for your "ports"?Pitterpatter
I
9

If a tree falls in the forest with no one around to hear, does it make a sound? Make sure it does:

using System;

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

class Test {
    ~Test() { Console.Beep(); }
}

The finalizers of any objects left at program termination are called just before the process terminates. The only way this won't happen is when the process is rudely aborted. Environment.FailFast() for example.


This answer is getting dated, I need to edit to point out that the rules changed for .NETCore (aka .NET 5.0 and up). In the legacy framework, finalizers were called when the AppDomain was getting unloaded. Most typically at program termination. AppDomains however became unsupported in .NETCore, along with it is the loss of guarantee that finalizers are getting called.

Ingrown answered 5/3, 2011 at 1:26 Comment(2)
And what happens when you put new Test() in another static function, call that new static Function from Main, and Application.Run(new Form1()) inside Main? I highly doubt GC will finalize that Test class until you close App or call GC.Collect(); ;)Jurado
The Console.Beep() is neat and I was not aware of this functionality in System.Console or haven't started using it yet. Anyways, instead of Environment.FailFast you could run these two lines at the end of execution : GC.Collect(); GC.WaitForPendingFinalizers(); But the two lines above have side effects such as making it slower to exit the program and kill the process.Survey
P
3

In 2023, when terminating a .NET application, finalizers are (most likely) never called, as stated on MSDN:

.NET 5 (including .NET Core) or a later version: There's no output, because this implementation of .NET doesn't call finalizers when the application terminates.

Sure most of us are using .NET 5 or later at this point. Thus, don't rely on this behavior unless you plan to stick with .NET Framework or running some non-Windows compatible .NET implementation (e.g. some cloud provided Linux version).

Instead, use IDisposable as some have sugggested here.

Procuration answered 30/11, 2023 at 16:14 Comment(1)
I could call the Finalizer on-demand using these two lines in a .NET 8 console app : GC.Collect(); GC.WaitForPendingFinalizers(); But "Just because you can, doesn't mean you should" as you should rely on the framework cleaning up. But if you have to call the finalizer for some reason and want to be sure it will call, these two lines running at the end should help out to trigger the finalizer call.Survey
Y
2

Finalizer is called by garbage collector and the garbage collection is not a predictable process hence it is not very reliable. You need to figure out other means to dispose your resources.

Yuzik answered 5/3, 2011 at 0:55 Comment(6)
C# does not have destructors. Those things that use C++ destructor syntax -- they are finalizers.Barrus
The OP was referring to it as destructor and later got edited.Yuzik
@Ben Voigt: Actually, the C# Programming Guide calls them destructors: msdn.microsoft.com/en-us/library/66x5fx1b.aspxEcholocation
@Ben: They are called "destructors" in C# and "finalizers" in the CLR. It is unfortunate that the two teams chose different terminology; if we had to do it all over again, we'd probably try to be more consistent. But it is completely wrong to say that C# does not have destructors. C# has destructors; the spec calls them destructors, the documentation calls them destructors, and they are implemented by overriding the finalizer.Sutherlan
@Eric: The documentation is flat-out WRONG. It says that "destructor syntax in C# and C++" are equivalent. I've already filed documentation feedback. I think it's correct to say that "In C#, C++ destructor syntax is used to create a CLR finalizer." It is destructor syntax, maybe it can even be called a "C# destructor", but it is not a destructor in the general sense. So I'm going to continue to encourage people to use the word finalizer, it's unambiguous and obviously related to finalization in the C# and CLR specs.Barrus
@Ben: I encourage you to do that if it makes you happy. Regarding the documentation, I assume the line you are upset with is "Provide implicit control by implementing the protected Finalize on an object (destructor syntax in C# and C++)." Though that sentence is awkwardly written and probably not grammatical, I don't see any error in it, aside from the fact that it probably should have said C++/CLI rather than just C++. I wouldn't have used a parenthetical; I'd have written two sentences.Sutherlan

© 2022 - 2024 — McMap. All rights reserved.