It seems like the things you want them to do, they actually don't provide the guarantees necessary to do them; and the things they are guaranteed to do, are so minimal that no one actually wants to do them.
It seems like the things you want them to do, they actually don't provide the guarantees necessary to do them; and the things they are guaranteed to do, are so minimal that no one actually wants to do them.
"So what, if anything, are finalizers good for? There are perhaps two legitimate uses. One is to act as a “safety net” in case the owner of an object forgets to call its explicit termination method. While there’s no guarantee that the finalizer will be invoked promptly, it may be better to free the resource late than never, in those (hopefully rare) cases when the client fails to call the explicit termination method. But the finalizer should log a warning if it finds that the resource has not been terminated, as this indicates a bug in the client code, which should be fixed. If you are considering writing such a safety-net finalizer, think long and hard about whether the extra protection is worth the extra cost.
...
A second legitimate use of finalizers concerns objects with native peers. A native peer is a native object to which a normal object delegates via native methods. Because a native peer is not a normal object, the garbage collector doesn’t know about it and can’t reclaim it when its Java peer is reclaimed. A finalizer is an appropriate vehicle for performing this task, assuming the native peer holds no critical resources. If the native peer holds resources that must be terminated promptly, the class should have an explicit termination method, as described above. The termination method should do whatever is required to free the critical resource. The termination method can be a native method, or it can invoke one."
.Net 2.0 introduced something called SafeHandle. SafeHandle inherits CriticalFinalizerObject which triggers special GC treatment of the finalizer. SafeHandle does a bunch of work to help you write a safe wrapper for an unmanaged/native handle.
You should almost never see a finalizer in modern C# code (there are extremely rare exceptions). Notice that the MSDN page for the dispose pattern[2] has [finally] been updated to omit the finalizer. The dispose pattern is the preferred way to do deterministic resource cleanup (in combination with SafeHandle for native resource cleanup). In .Net finalizers are now the wrong tool for the job in the majority of situations.
Another thing not mentioned in the article is that if you implement a finalizer your code becomes multithreaded. Once you have a finalizer your disposer needs to become thread-safe (and lock-free, you must never use a mutex in a finalizer). Finalizers are bad. Stay away from them.
[1]: http://blogs.msdn.com/b/bclteam/archive/2006/06/23/644343.as... [2]: https://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx
By cleaning up these things in the finalizer, they get deallocated during a long running process when the process encounters memory pressure and runs the GC, or they get cleaned up automatically when the program terminates.
An example is a Lock object that wraps a pthread_mutex. It's unreasonable to demand that every object that has a lock explicitly dispose of it; it's simpler to equip the Lock with a finalizer that can dispose of the underlying mutex.
I think one of the implied points of the article is that you should not rely on finalizers for anything time sensitive or critical. For instance, if you MUST close a file handle or database connection, you should never rely on a .NET finalizer to do it because it's not predictable when or if it will run. You should explicitly close it (most likely by implementing and calling Dispose().)
Because there is clearly value in doing certain very specific things when objects become unreachable.
The same mechanism on which finalizers are built does useful things like expire entries out of weak hash tables or "lapse" weak references to safe values.
Now suppose you have some special baggage ("external resources") associated with weak hash table entries. You'd like to dispose of it when the entries disappear. That looks like a very good case for extending the finalization mechanism with user-defined hooks.