15.1 The Garbage Collector

C# depends on the CLR for many of its runtime services, and
garbage collection is no exception.

The CLR includes a high-performing generational mark-and-compact
garbage collector (GC) that performs automatic memory management for
type instances stored on the managed heap.

The GC is considered to be a tracing
garbage collector in that it doesn't interfere with
every access to an object, but rather wakes up intermittently and
traces the graph of objects stored on the managed heap to determine
which objects can be considered garbage and therefore collected.

The GC generally initiates a garbage collection when a memory
allocation occurs and memory is too low to fulfill the request. This
process can also be initiated manually using the
System.GC type. Initiating a garbage collection
freezes all threads in the process to allow the GC time to examine
the managed heap.

The GC begins with the set of object references considered roots, and
walks the object graph, marking all the objects it touches as
reachable. Once this process is complete, all objects that have not
been marked are considered to be garbage.

Objects that are considered garbage and don't have
finalizers are immediately discarded, and the memory is reclaimed.
Objects that are considered garbage and do have finalizers are
flagged for additional asynchronous processing on a separate thread
to invoke their Finalize methods before they can
be considered garbage and reclaimed at the next collection.

Objects considered still live are then shifted down to the bottom of
the heap (compacted), hopefully freeing space to allow the memory
allocation to succeed.

At this point the memory allocation is attempted again, the threads
in the process are unfrozen, and either normal processing continues
or an OutOfMemoryException is thrown.