Stefano d'Antonio Stefano d'Antonio - 6 months ago 23
C# Question

Garbage collection of local objects

I wrote a small Console app experiment:

static void Main()
{
int GetTotalCollections()
{
var total = 0;

for (var generation = 0; generation <= GC.MaxGeneration; generation++)
total += GC.CollectionCount(generation);

return total;
}

CreateGarbage();

WriteLine("Number of collections occurred: {0}", GetTotalCollections());
}

static void CreateGarbage()
{
WriteLine(new object().GetHashCode());
WriteLine(new object().GetHashCode());
WriteLine(new object().GetHashCode());
ReadKey();
}


When I run it in
Release
mode without the debugger attached, I get
0
collections for all the generations.

As it seemed weird, I attached
WinDbg
to the process and
!dumpheap -live
does not show the objects whereas
!dumpheap
does. Unfortunately
-live
is not part of the official documentation for SOS, but I was assuming it showed only uncollected objects.

Is the
GC
collecting and not reporting it (as it should be in this scenario) or have I misunderstood the
!dumpheap -live
output? (maybe showing only object with a
GC root
?)

If I allocate more objects to be sure I trigger a collection (or invoke
GC.Collect
) I get a collection count increase, but still the same output in WinDbg:


static void GetValue()
{
for (var i = 0; i < 1000000; i++)
new object();

ReadKey();
}


EDIT: The last sentence was an oversight (which caused the confusion), if I force the collection,
!dumpheap -stat
does not show the objects any more as expected (I just forgot to run the app from
WinDbg
before pressing a key to force the collection.)

!dumpheap -stat
shows uncollected objects both live and dead and
!dumpheap -stat -live
shows only objects with a
GC root
as @Thomas answered. Once collected they disappear from the output of all the commands.

Answer Source

Unfortunately -live is not part of the official documentation for SOS

When I type !help dumpheap, it says:

-live     Only print live objects
-dead     Only print dead objects (objects which will be collected in the
          next full GC)

Live objects are objects that are referenced by a garbage collection root and dead objects are objects that have no such reference any more and can be garbage collected whenever .NET thinks it's time to do that.

You should be able to find the difference when you run !gcroot on a live object and on a dead object. The live object should be connected to a root (pinned handle, thread, static variable, freachable queue, ...) but the dead object is not.

Example for a dead object:

0:007> !gcroot -all 029e3be4
Found 0 roots.

Example for a live object:

0:007> !gcroot -all 029e406c
HandleTable:
    00b913f0 (pinned handle)
    -> 039e24d0 System.Object[]
    -> 029e406c System.String

Found 1 roots.
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download