- Finalization is a mechanism offered by the CLR that allows an object to perform some graceful cleanup prior to the garbage collector reclaiming the object's memory.
- Finalizers should release unmanaged resources only. You very rarely need to use finalization with managed resources.
- Any type that wraps a native resource, such as a file, network connection, socket, mutex, or other type, must support finalization.
- The framework does not guarantee that a finalizer will execute at all on any given instance.
- Basically, the type implements a method named Finalize. When the garbage collector determines that an object is garbage, it calls the object's Finalize method.
- The earlier versions of the C# Programming Language Specification called this method a destructor.
- The problem is that developers mistakenly believe that using the C# destructor syntax means that the type's objects will be deterministically destructed, just as they would be in C++. However, the CLR doesn't support deterministic destruction.
- In version 2 of the C# Programming Language Specification, a method using this syntax is now officially called a finalizer.
- You have no control over when the Finalize method will execute.
- The CLR doesn't make any guarantees as to the order in which Finalize methods are called
What Causes Finalize Methods to Be Called:
Finalize methods are called at the completion of a garbage collection, which is started by one of the following five events. The following force a GC to start:
- Generation 0 is full (most common way for Finalize methods to be called)
- Code explicitly calls System.GC's static Collect method (Microsoft strongly discourages)
- Windows is reporting low memory conditions (If Windows reports low memory, the CLR will force a garbage collection in an effort to free up dead objects to reduce the size of a process' working set.)
- The CLR is unloading an AppDomain.
- The CLR is shutting down.
What might cause the Finalize method not to execute:
- The CLR uses a special, dedicated thread to call Finalize methods. For the above first four events, if a Finalize method enters an infinite loop, this special thread is blocked, and no more Finalize methods can be called. This is a very bad situation because the application will never be able to reclaim the memory occupied by the finalizable objects—the application will leak memory as long as it runs.
- Under low memory conditions, the CLR might not be able to find enough memory in order to compile the Finalize method, which would prevent it from executing causing the native resource to leak.
- Or the resource might not be freed if the Finalize method contained code that referred to a type in another assembly, and the CLR failed to locate this other assembly.
- You can use CriticalFinalizerObject class which guarantees that the native resource will be released.
- The SafeHandle-derived classes are extremely useful because they ensure that the native resource is freed when a garbage collection occurs.