GC and Unmanaged Code
Applications often have to deal with objects that are created outside of the .NET managed environment. For example, they might be accessing the file system or using a database connection. These objects need to manage their own memory, including cleaning up after themselves. They can expose Finalizer/Destructor methods which the application can call when it is finished with the unmanaged object to tell it to clean up prior to destruction. The simplified GC process described earlier needs to be modified to ensure that unmanaged objects have their Finalizer called prior to destruction.
When an unmanaged object is created (added to the heap and referenced from the stack), a second reference to it is added to the Finalization Queue, effectively a list of all finalizable objects. This queue is counted as an application root for GC purposes, so any object that is referenced from the Finalization Queue is considered alive.
Finalizers can take a while to run (say if they need to close files or communicate with a database), but remember that the shorter the GC runs, the better the user experience.
The solution is to ensure that the GC does not run any Finalizers, instead these are run on a separate thread without the application needing to pause (remember these objects are no longer being used by the application so there is no potential for interference).
When an object is ready to be finalized, the GC puts a reference to it on the fReachable Queue. The fReachable queue contains objects which have a reachable finalizer that needs to be run at the earliest opportunity.