3

I wanted to add a small debug UI to my OpenGL game, which will be updated frequently with various debugging options/output displays. One thing I wanted was a constant counter that shows active objects in each generation of the garbage collector. I don't want names or anything, just a total count; something that I can eyeball when I do certain things within the game.

My problem, however, is that I can't seem to find a way to count the total objects currently alive in the various generations.

I even considered keeping a global static field, which would be incremented within every constructor and decremented within class finalizers. This would require hand-coding said functionality into every class though, and would not solve the problem of a "per-generation total".

Do you know how I could go about doing this?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Krythic
  • 4,184
  • 5
  • 26
  • 67
  • I'd look into [*ClrMD*](https://github.com/Microsoft/dotnetsamples/tree/master/Microsoft.Diagnostics.Runtime/CLRMD) instead – Yuval Itzchakov Jun 14 '15 at 05:18
  • In case that you will not get a simpler answer, you could attempt to use the CLR's unmanaged debugging & profiling APIs to inspect the GC: see [this answer](http://stackoverflow.com/a/30347622/240733) to this [similar question](http://stackoverflow.com/q/30346990/240733 "How to list all object in GC finalization list?"). – stakx - no longer contributing Jun 14 '15 at 12:54
  • Suggestion: It might be easier to just profile your application with a standalone .NET memory profiler. – stakx - no longer contributing Jun 14 '15 at 14:57

2 Answers2

3

(Question title:) "Counting total objects queued for garbage collection"

(From the question's body:) "My problem, however, is that I can't seem to find a way to count the total objects currently alive in the various generations."

Remark: Your question's title and body ask for opposite things. In the title, you're asking for the number of objects that can no longer be reached via any GC root, while in the body, you're asking for "live" objects, i.e. those that can still be reached via any GC root.

Let me start by saying that there might not be any way to do this, basically because objects in .NET are not reference-counted, so they cannot be immediately marked as "no longer needed" when the last reference to them disappears or goes out of scope. I believe .NET's mark-and-compact garbage collector only discovers which objects are alive and which can be reclaimed during an actual garbage collection (during the "mark" phase). You however seem to want this information in advance, i.e. before a GC occurs.

That being said, here are perhaps your best options:

  1. Perhaps your best bet in .NET's managed Framework Class Library are performance counters. But it doesn't look like there are any suitable counters available: There are performance counters giving you the number of allocated bytes in the various GC generations, but AFAIK no counters for the number of live/dead objects.

  2. You might also want to take a look at the CLR's (i.e. the runtime's) unmanaged, COM-based Debugging API. Given that you have retrieved an ICorDebugProcess5 interface, these methods might be of interest:

    "Gets an enumerator for all objects that are to be garbage-collected in a process."

    See also this answer to a similar question on SO.

    Note that this is about objects that are to be garbage-collected, not about live objects.

    "Provides general information about the garbage collection heap, including whether it is currently enumerable."

    If it turns out that the managed heap is enumerable, you could use…

    "Gets an enumerator for the objects on the managed heap."

    The objects returned by this enumerator are of this type:

    "Provides information about an object on the managed heap."

    You might not be actually interested in these details, but just in the number of objects returned by the enumerator.

    (I haven't used this API myself, perhaps there exists a better and more efficient way.)

  3. In Sept 2015, Microsoft published a managed library called clrmd aka Microsoft.Diagnostics.Runtime on GitHub. It is based on the same foundation as the unmanaged debugging API mentioned above. The project includes documentation about enumerating objects in the GC heap.

Btw. there is an extremely informative book out there by Ben Watson, "Writing High-Performance .NET Code", which includes solid tips on how to make .NET memory allocation and GC more efficient.

Community
  • 1
  • 1
stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
  • I accepted you as the answer, but I don't feel as though your initial remark was valid. I feel as though the title was completely synonymous with the body. – Krythic Jun 14 '15 at 21:22
1

Garbage Collector doesn't have to collect objects.

... that fact will be discovered when the garbage collector runs the collector for whatever generation the object was in. (If it runs at all, which it might not. There is no guarantee that the GC runs.)

(C) Eric Lippert

If the application performs normally and the memory consumption is not increasing the GC can let it work without interruptions. That means that numbers will differ from run to run.

If I were you I wouldn't spend time on getting generations information, but just the size of used memory.

The simple but not very accurate way is to get it from GC.

    // Determine the best available approximation of the number  
    // of bytes currently allocated in managed memory.
    Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

If you see that used memory increases and decreases often, then you can use existing profilers to figure out where are you allocating too mush, or even where the memory leak is.

Community
  • 1
  • 1
Anton Sizikov
  • 9,105
  • 1
  • 28
  • 39
  • I sort of agree with the general direction your answer goes into (esp. the third paragraph), but could you perhaps elaborate on what you mean by _"garbage collector doesn't have to collect objects"_? – stakx - no longer contributing Jun 14 '15 at 14:53
  • @stakx I meant that GC may not run and finalize your objects before (and even after) your app is terminated. http://blogs.msdn.com/b/oldnewthing/archive/2010/08/09/10047586.aspx – Anton Sizikov Jun 14 '15 at 15:01