3
\$\begingroup\$

I'm concerned about how much time my application could be spending during garbage collection so I'm trying to figure out how to add some code to instrument this.

Based on some examples:

I've come up with the code below. I'm see GC taking around 200 ms locally. Does anyone know if the code below is reasonable? Or is there a better way?

class Program
{
 public static void Main(string[] args)
 {
 var done = false;
 var load = new List<byte[]>();
 var pollGC = new Action(() =>
 {
 // Register for a notification. 
 GC.RegisterForFullGCNotification(10, 10);
 Console.WriteLine("Registered for GC notification.");
 Stopwatch gcTimer = new Stopwatch();
 while (!done)
 {
 // Check for a notification of an approaching collection.
 GCNotificationStatus s = GC.WaitForFullGCApproach();
 if (s == GCNotificationStatus.Succeeded)
 {
 Console.WriteLine("GC is about to start.");
 load.Clear();
 gcTimer.Restart();
 }
 // Check for a notification of a completed collection.
 s = GC.WaitForFullGCComplete();
 if (s == GCNotificationStatus.Succeeded)
 {
 Console.WriteLine("GC has finished in {0} ms", gcTimer.ElapsedMilliseconds);
 }
 Thread.Sleep(500);
 }
 GC.CancelFullGCNotification();
 Console.WriteLine("Finished monitoring GC");
 });
 var doWork = new Action(() =>
 {
 while (!done)
 {
 try
 {
 load.Add(new byte[10000]);
 }
 catch (OutOfMemoryException)
 {
 Console.WriteLine("Out of memory. {0}", load.Count);
 }
 }
 });
 Console.WriteLine(GCSettings.IsServerGC);
 Task.Run(pollGC);
 Task.Run(doWork);
 Console.ReadLine();
 done = true;
 GC.CancelFullGCNotification();
 Thread.Sleep(2000);
 }
}
200_success
145k22 gold badges190 silver badges478 bronze badges
asked May 6, 2015 at 17:33
\$\endgroup\$
2
  • \$\begingroup\$ Who's marking this as "broken code"? The OP says it seems to be working properly. \$\endgroup\$ Commented May 6, 2015 at 20:10
  • \$\begingroup\$ @Snowbody That code is broken. Will explain in answer. \$\endgroup\$ Commented May 8, 2015 at 22:36

2 Answers 2

2
\$\begingroup\$

Your design won't work. You're starting a timer using GC.WaitForFullGCApproach. But this method only indicates that a Full GC is imminent (not starting). It actually allows you some time to prepare for it and force a GC yourself using GC.Collect. Your numbers won't be accurate.

Why not try using the memory performance counters?

Alternatively you could do this:

while (!done)
{
 if (GC.WaitForFullGCApproach() == GCNotificationStatus.Succeeded)
 {
 //TODO - Do GC preparation here if need be
 Console.WriteLine("Full GC is imminent. Starting a GC manually.");
 load.Clear();
 gcTimer.Restart();
 GC.Collect();
 gcTimer.Stop();
 Console.WriteLine("GC has finished in {0} ms", gcTimer.ElapsedMilliseconds);
 GC.WaitForFullGCComplete();
 }
}
answered May 8, 2015 at 22:38
\$\endgroup\$
3
  • \$\begingroup\$ None of those performance counters report how long garbage collection is taking (as far as I can tell). \$\endgroup\$ Commented May 11, 2015 at 16:16
  • \$\begingroup\$ % time in GC is effectively how long it's taking. But if you need absolute numbers I would suggest doing a call to GC.Collect in response to an approach notification and using a Stopwatch to measure just that. \$\endgroup\$ Commented May 11, 2015 at 18:50
  • \$\begingroup\$ I'd rather not force a garbage collection myself...as I'm not trying to alter the 'normal' GC behavior...I'm just trying to monitor it. But as there doesn't seem to be any other way, I'll mark this as the 'answer'. \$\endgroup\$ Commented May 13, 2015 at 12:12
3
\$\begingroup\$

For continuous monitoring I agree with Zer0 to look at the % time spent in GC performance counters.

However for a session based analysis a more informative approach would be to collect the ETW traces from .NET. You can see here for the different GC related events, GCStart and GCEnd would most likely be relevant for you.

view the .NET documentation for Garbage Collection ETW Events

You can specify the GC Collect Only option exists which would be very useful here.

The GC Collect Only Checkbox - Turns off all providers except those that describe garbage collections. Thus even the GC allocation sampling is turned off. This mode logs even less data than GC Only, and thus can collect data over an every longer period of time (say a day) in reasonable size (say 200 meg). The /GCCollectOnly command line option achieves the same effect.

Sᴀᴍ Onᴇᴌᴀ
29.5k16 gold badges45 silver badges201 bronze badges
answered Sep 18, 2019 at 12:25
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.