Held and Reachable Instances
Several views in .NET Memory Profiler present information about held and reachable instances, e.g., the instances list under Type details and the instance references tree. Below is an explanation of the terms reachable and held instances.
Reachable instances includes all instances that are reachable from a base instance, including the base instance itself. Consequently, reachable bytes is the number of bytes used by the reachable instances.
Held instances, on the other hand, only include instances that are uniquely reachable from the base instance. If a reachable instance can be reached from another root, without passing through the base instance, then it will not be counted as reachable.
Consider the following instance graph:
In the graph above, instance #1 references two child instances, plus some other instances. The child instances (#4 and #5) have a reference back to their parent. This is a very common scenario in hierarchical structures (e.g. controls in a Windows Forms application).
Reachable from instance #1
In the graph below, the instances that are reachable from instance #1 have been colored green. Compare this with the next graph.
Held by instance #1
In the graph below, the instances that are held by instance #1 are colored red.
As can be seen, instance #6 is not colored, even though it is reachable from instance #1. The reason for this is that instance #6 is not uniquely reachable from instance #1. It can also be reached from root #2, via instance #2, without passing through instance #1.
Reachable from instance #5
In the graph below, the instances that are reachable from instance #5 have been colored green.
It can be noted that the reachable instances are the same as the reachable instances from instance #1. This happens because instance #5 references instance #1. If two instances have references to each other, the reachable instances will by definition be the same. Compare this with the next graph.
Held by instance #5
In the graph below, the instances that are held by instance #5 are colored red.
Since instance #1 can be reached from a root without passing through instance #5, it will not be considered to be held by instance #5.
From the example above, it can be seen that held instances (and bytes) provides a better metric for the total memory usage of an instance than the reachable instances. The reachable instances metric will include too many instances to be meaningful in a scenario like this parent-child relationship.
Unfortunately, none of the metrics is perfect, since the held instances metric will not count the memory usage of shared instances. Instance #6 in the example is not held by any instance (except itself), since it is shared by both instance #1 and #2.
Held by a Set of Instances
The concept of held instances can be extended to sets of instances as well. In the graph below, the instances that are held by the instance set containing instance #1 and instance #2 are colored red.
It can be noticed that instance #6 is neither held by instance #1 alone, nor by instance #2 alone. However, if instance #1 and #2 are considered simultaneously, instance #6 will be held, since it is not reachable from any root without passing through instance #1 or #2.
Information about the number of instances (and bytes) held by a set of instances can be a useful metric of the total memory usage of the instances.
Under the Overview page, information about held bytes for each type and filter is presented by default. This gives a better idea about the total memory usage of a specific type or filter.