Are .net finalizers always executed?
Asked Answered
C

2

19

Are finalizers guaranteed to be executed in .NET at some point (spare power outages and the like)? I know how GC works and that it is nondeterministic when exactly they'll run.

(The search did not display good answers, so I'm adding this question in high expectation of a merge with the not-so-easy-to-discover actual answers. Apart from that, I already know the answer and am going to add it after a few days in case nobody mentioned it.)

Coper answered 11/8, 2010 at 12:26 Comment(0)
F
26

Finalizers may actually be never executed, as Raymond Chen explains. Kind of funny that this question is asked during his annual CLR week, just two days after he explained it :)

For the lazy ones, the (or rather, one) conclusion is:

A correctly-written program cannot assume that finalizers will ever run.

If you are wondering whether you can rely on finalizers, this is already everything you have to know: Don't rely on finalizers.

As Raymond Chen also states in the linked article:

Finalizers are a safety net, not a primary means for resource reclamation.

If you're looking for how to release resources, have a look at the Disposable pattern.


A finalizer may not run, for example, if:

  • Another finalizer throws an exception.
  • Another finalizer takes more than 2 seconds.
  • All finalizers together take more than 40 seconds.
  • An AppDomain crashes or is unloaded (though you can circumvent this with a critical finalizer (CriticalFinalizerObject, SafeHandle or something like that)
  • No garbage collection occurs
  • The process crashes

(Note: The time values may have changed over time, but were certainly true some time ago.)

I guess there are a lot more things that can cause finalizers to never run. The bottom line is, other than the quote from Mr. Chen, that finalizers are a safety net that decrease the impact of bugs, because for example resources are released sometime, which is better than never, if you forget to do it explicity.

Fionafionna answered 11/8, 2010 at 12:30 Comment(6)
Could you quote more of the important parts? And yes, maybe the asker was looking forward to exactly that link. ;)Coper
Actually, since many people ask how they can rely on finalizer behaviour, I think I did quote the single most important part ;) On the other hand, the other boxes in the article may be interesting as well.Fionafionna
@OregonGhost: Am I understanding this right: if 20 finalizers each take 1.95 seconds each, that's hunky dory and all will execute--taking 39 seconds. If one takes 2.05 seconds, execution of all the others is skipped. That seems rather broken. Rather rudely interrupting a finalizer that takes over 2 seconds, for the purpose of allowing other ones to run for the remainder of the 40-second timeout, would be a good feature. But clobbering things after two seconds would seem a misfeature.Mislike
@supercat: I don't know if it is exactly like you describe, I just read the article I linked, which on the other hand claims that the behaviour might have been changed over the years. Don't forget that you should never rely on finalizers, so I think it's kind of fine. You have to make a cut somewhere. If you think 2.05 seconds should be ok, what's with 2.10? 2.15? 3? 5? You don't really want to wait 40 seconds before the app is gone, it's just a third-level safety net (after running finalizers at all, and waiting 2 seconds for each one). Apps are not supposed to take 40 seconds to shutdown.Fionafionna
@OregonGhost: I think a two-second limit on a finalizer would probably be a generally good thing, if imposing the limit would allow other finalizers to run; one could perhaps reduce the limit with time (eg. .so each finalizer gets 5% of the time remaining before a 40-second limit). As for not relying on finalizers, what other mechanism will signal objects to save their state when the application is being killed off?Mislike
@supercat: When the application is being killed, finalizers won't run anyway. If you just want anyone (all your objects) to release resources or save their state on a normal exit, use IDisposable. If you have some kind of handle that should be released even if e.g. your app domain crashes, use SafeHandle. I never needed to write a single finalizer in any .NET code I ever wrote. C++ destructors also translate to IDisposable.Dispose, in C++/CLI, and not to a finalizer. Because of all that, I think the simple timeout system used in the CLR is fine, though yours would be as well.Fionafionna
M
6

If a finalizer throws an exception, other finalizers will not execute.

You can also suppress finalizers if you call SuppressFinalizer on the object.

From MSDN (Object.Finalize):

The Finalize method might not run to completion or might not run at all in the following exceptional circumstances:

  • Another finalizer blocks indefinitely (goes into an infinite loop, tries to obtain a lock it can never obtain and so on). Because the runtime attempts to run finalizers to completion, other finalizers might not be called if a finalizer blocks indefinitely.
  • The process terminates without giving the runtime a chance to clean up. In this case, the runtime's first notification of process termination is a DLL_PROCESS_DETACH notification.
Monometallism answered 11/8, 2010 at 12:27 Comment(3)
Could you add a source for the "exception" part?Coper
Note that "goes into an infinite loop" does, in the CLR implementation, mean "takes more than two seconds", as explained here: nitoprograms.blogspot.com/2009/08/…Fionafionna
@mafutrct - See here: #1539130Monometallism

© 2022 - 2024 — McMap. All rights reserved.