The garbage collector runs in its own thread and can execute only at certain times—typically, when your application reaches the end of a method and the CLR decides that it would be beneficial to reclaim memory. While it runs, other threads that are running in your application temporarily halt. This is because the garbage collector might need to move objects around and update object references; it cannot do this while objects are in use.
The steps that the garbage collector takes are as follows:
1. It builds a map of all reachable objects. It does this by repeatedly following reference fields inside objects. The garbage collector builds this map very carefully and makes sure that circular references do not cause an infinite recursion. Any object that is not in this map is deemed to be unreachable.
2. It checks whether any of the unreachable objects has a destructor that needs to be run (a process that is called finalization). Any unreachable object that requires finalization is placed in a special queue that is called the freachable queue.
3. It deallocates the memory for the remaining unreachable objects (those that don’t require finalization) by moving the reachable objects down the heap. This action defragments the heap and frees memory at the top of the heap. When the garbage collector moves a reachable object, it also updates any references to the object.
4. At this point, it allows other threads to resume.
5. It finalizes the unreachable objects that require finalization (held in the freachable queue) by using its own thread.
Writing classes that contain destructors adds complexity to your code and to the garbage
collection process, and makes your program run more slowly. If your program does not
contain any destructors, the garbage collector does not need to place unreachable objects
in the freachable queue and finalize them. Only use destructors when you really require
them. You must be very careful when you write a destructor. In particular, be aware that, if
your destructor calls methods of other objects, the garbage collector may have already
called those other objects. Remember that the order of finalization is not guaranteed.
Therefore, ensure that destructors do not depend on each other or overlap with each other
(for example, do not have two destructors that attempt to release the same resource).