Finalizers are a C# construct that ensures that any required bookkeeping is performed when the
Garbage Collector collects an object.
They are run even if the constructor fails, so program a finalizer as though everything could go wrong. Don't rely on state.
EditReasons to Not Use Finalizers in Managed Code
- Finalizers take longer to construct because pointers to them must be placed on the finalization list.
- They get promoted to older generations when the garbage collector collects, increasing memory pressure, and preventing an object from being collected when the GC determines the object is garbage. All objects referenced by this object also get promoted as a result.
- They cause the application to run slower because of extra processing at collection.
- When the objects are finalized is indeterminate. They're at the mercy of the GC.
EditHow the CLR Handles Finalizers During Garbage Collection
1. When the
new operator is called, the finalizer is added to a finalization list before the constructor is called.
2. When collected, if the item exists in the finalization list, the GC places the item in the Freachable ("F-Reachable") queue and leaves the object's memory in the managed queue.
3. A dedicated
thread starts running the finalizers that have been added to the Freachable queue. For this reason, avoid specifically multithreaded code within finalizers. Also, this is subject to change, so avoid any code assuming that finalizers will be run serially. Also, ensure finalizers are not called in an infinite loop, otherwise, the other items in the Freachable queue will not be executed, and the app will begin leaking memory.
4. After the items in the Freachable queue are finalized, they are truly garbage, and ready for their memory to be reclaimed.
Due to this process, two garbage collections are needed to remove objects that have a finalizer.
If a finalizer takes more than two seconds to return, and the CLR is exiting, the CLR will no longer call finalizers, and will instead kill the
process.
EditWriting a Finalizer
It's important not to construct new objects if either the
AppDomain.IsFinalizingForUnload or the
Environment.HasShutDownStarted properties return true.