dotMemory 2016.1 Help

Analyzing GC Roots

Retention path of an object always starts with a GC root. From the point of Garbage Collector, root is a
reference to
an object that must not and will not be collected. This makes roots the only possible starting point for
building
retention graphs. Understanding root types can be extremely important in the "Who retains the object?" analysis.
Sometimes, examining retention paths does not give you an answer why the object is still in memory.
In this case, it makes sense to look at GC roots. For example, the
RefCounted handle gives you a clue that the object is retained by some unmanaged COM library.

There are following possible roots in .NET Framework:

Stack references - references to local objects. Such roots live during a method execution.

Static references - references to static objects. These roots live the entire app domain life time.

Handles - typically, these are references used for communication between managed and unmanaged code. Such roots must
live
at least until the unmanaged code needs "managed" objects.

Finalizer references - references to objects waiting to be finalized. These roots live until the finalizer is run.

Regular local variable

This is a local variable declared in a method (variable on the stack). Reference to this variable becomes a root
during the method life time.
For example:

staticvoidMain(){...varcollection=newCollection<int>();...}

Note that in release builds, root's life time may be shorter - JIT can discard the variable right after it is no
longer needed.

Static reference

When CLR meets static object (class member, variable, or event), it creates a global instance of this object. The
object can be accessed during the entire app life time, so static objects are almost never collected. Thus,
references to static objects is one of the main root types.

classStaticClass{publicstaticCollection<string>StCollection;}

After the collection is initialized, CLR will create a static instance of the collection. The reference to the
instance will exist during the application domain life time.

When the static object is referenced through a field, dotMemory shows you field's name.

Of course, "unnamed" static references can also take place. The most obvious example of such a root is a
reference to a string declared in a method.

staticvoidMain(){...stringA="This is a string";...}

Note, that in the example above, the Regular local variable
reference is also created by CLR. But, to simplify
further analysis, dotMemory doesn't show you this root.

Pinning handle

Interaction of managed and unmanaged code is an additional problem for Garbage Collector. For example, you need
to pass an object from the managed heap to, say, an external API library. As a small object heap is compacted
during collection, the object can be moved. This is a problem for the unmanaged code if it relies on the exact
object location. One of the solutions is to fix the object in the heap. In this case, GC gets a pinning handle
to the object which implies that the object cannot be moved.
Thus, if you see the Pinning handle
type, then probably the object is retained by some unmanaged code.
For example, the App object always has a pinning reference.

Note: You can also pin objects intentionally using the
fixed block.

RefCounted handle

The root prevents garbage collection if the reference count of the object is a certain value.
If an object is passed to a COM library using COM Interop, CLR creates a RefCounted handle to this object. This
root is needed as COM is unable to perform garbage collection. Instead, it uses reference counting. If the
object is no longer needed, COM sets the count to 0. This means that RefCounted handle is no longer a root and
the object can be collected.

Thus, if you see
RefCounted handle, then, probably, the object is passed as an argument to unmanaged code.

Weak handle

As opposed to other roots, the Weak handle does not prevent referenced objects from garbage collection. Thus,
objects can be collected at any time but still can be accessed by the application. Access to such objects is
performed via an intermediate object of the WeakReference class. Such an approach can be very efficient when
working with temporary data structures like cache.
As weak references do not survive full garbage collection, the weak reference handle can come only in
combination with other handles. For example,
Weak, RefCounted handle.

Regular handle

When handle type is undefined, dotMemory marks it as Regular handle. Typically, these are references to system
objects required during the entire app life time. For example, the
OutOfMemoryException
object. To prevent its
collection, the environment references the object through a regular handle.