
Myths about finalizers, part two - AndrewDucker
http://ericlippert.com/2015/05/21/when-everything-you-know-is-wrong-part-two/
======
copsarebastards
Garbage collection is a leaky abstraction and finalizers are the edge where it
leaks.

I tend to think that using finalizers is almost always a bad idea. They're
just too complicated: there's no way you can reason about them effectively.
This long list of assumptions you can't make about finalizers is just an
example of this: if you have to keep all of this in mind you're forgetting
something else. Luckily there are alternatives.

~~~
bunderbunder
That's what Eric Lippert's trying to get at here, in tortuously brutal detail.
Here's the last line of the post again:

    
    
      It is therefore very difficult indeed to write a correct
      finalizer, and the best advice I can give you is to not try.
    

Since the initial release, .NET has come up with additional mechanisms to try
and minimize the number of situations where you would need to implement a
finalizer. At this point I find that it's always possible to avoid one. When I
think I need one, I ask myself the following question: "Am I hacking on the
core framework?" If the answer is no, then I probably shouldn't be writing a
finalizer.

~~~
StillBored
Well, it always seemed to me that the one good use for a finalizer was to make
sure that the coder remembered to call the Dispose() method...

AKA say you have a resource (like a file handle) that is being wrapped by a
class. In C++ the constructor would open the file, and the destructor would
close it. In a GC'ed environment because you can't determine when the instance
is going to get cleaned up the programmer ends up calling a .close() or
Dispose() method instead of the destructor. So the finalizer ends up just
being a little piece of code that says, did the user remember to call close?
No? Complain loudly enough someone will fix it.

~~~
bunderbunder
The preferable options in these sorts of situations generally boil down to:

    
    
      1. Use a SafeHandle or CriticalHandle
      2. Let the finalizers for the resources you're holding take care of themselves.
    
    

#2 because if your resources already have their own finalizers (e.g., streams,
db connections), then implementing your own is like a belt and suspenders.
Except that whichever one you added 2nd is probably broken and makes
everything strictly worse.

~~~
StillBored
Sure, there are other strategies for handling the problem. But many have
latent bugs, which is mostly what this article is pointing out.

In your case 2, unless you try to force the finalizer to run (he has a
collect/waitforpendingfinalizers sequence in one of his examples) this
potentially leaves the resource consumed for an indeterminate amount of time.

Its also not clear to me that the *Handle routines guarantee correct behavior
with processes running outside of the CLR. I just looked at the docs and it
reenforced my understanding that they seem to be strictly designed to protect
.net applications from shooting themselves in the foot. I'm not a .net/CLR
expert so take that for what its worth.

------
jscottmiller
If you're working with .net code that uses finalizers (especially if those
sections were written by people unlikely to read articles like this, though
good programmers screw this up too), chances are that there are latent issues
in your application that will manifest as sudden application crashes with
little to no debugging information.

I found myself in such a situation. Books like Advanced .NET Debugging [1]
will help you regain your sanity.

[1] [http://www.amazon.com/Advanced-NET-Debugging-Mario-
Hewardt/d...](http://www.amazon.com/Advanced-NET-Debugging-Mario-
Hewardt/dp/0321578899)

~~~
copsarebastards
TBH if you need to do advanced debugging, it might be better to just not use
finalizers.

------
jontro
I've never had to use finalizers in java. When is this functionality actually
needed? Any examples when it's used. In java finalizers may not be run at all
afaik.

~~~
copsarebastards
I haven't yet come across a case where it's actually needed, but I've come
across a few cases where it _seems_ like the easiest solution.

------
Dylan16807
Thankfully the worst of those problems is the easiest to deal with. Put a call
to GC.KeepAlive(this) at the end of your constructor. At least then you'll
have some sanity in the case that the finalizer runs.

