4 ms·
When everything you know about finalizers is wrong
- scarmig 11y agoIs there ever actually a good reason to use finalizers? Why do they even exist? 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.
- millstone 11y agoI think they make sense for the case of resources that need explicit deallocation, when their lifetime is not tied to a scope (e.g. multiple owners). 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.
- fleitz 11y agoExcept finalizers may not release the mutex if they aren't run
- SamReidHughes 11y agoIt depends whether or not mutexes are "heavy" resources. If making them and not using them is free, then it's OK to treat them like memory and wait for garbage collection to do its thing.
- eel 11y agoIf your application is a well-behaving application in a well-behaving environment, then it will most likely run in a reasonable amount of time. Furthermore, if you leak a few mutexes, it's not really a big deal for most applications. 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().)
- bradleyjg 11y agoNot for c#, but here's what Effective Java has to say on the matter for java: "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."
- mattchamb 11y agoI would put code in them that cleans up things that the OS would clean up anyway when the program terminates. Things such as unmanaged file handles and unmanaged memory handles. 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.
- kazinator 11y agoWe can separate that into the question: is there a good reason to have user-defined finalizers? 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.
- zamalek 11y agoThey are an artifact from .Net 1.0. They allowed developers to clean up native resources (file handles, satellite links, etc.) that they might have been wrapping. .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.aspx http://blogs.msdn.com/b/bclteam/archive/2006/06/23/644343.as... [2]: https://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx https://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx
- TheLoneWolfling 11y agoAre there any languages that get finalizers right? As in, are there any languages that at least make a best effort to run finalizers? To me, it seems like languages like Java and C# go "we can't do it in every conceivable situation, so let's punt it always". Not an ideal "solution". You don't see optimizers optimizing functions to "throw OutOfMemoryError", so why do they do the equivalent with finalizers?