My two cents on GC.Collect method in C#

Refrain from calling the GC.Collect method explicitly to reclaim the memory occupied by the objects in your application unless there is a specific reason do so

GC.Collect method

GC.Collect method

The GC.Collect() method has for long been popular among .Net developers. However, hardly few of us know how it actually works or, if a call to it is at all needed.

The CLR (Common Language Runtime) adopts garbage collection as a mechanism to clean up the resources consumed by your application. Note that when you create objects in .Net, they are stored in the managed heap, and when you are done using them, you need not worry about cleaning them -- the runtime would do it for you.

The CLR organizes the managed heap into generations. The three generations into which the managed heap is organized are: Generation 0, Generation 1, and Generation 2. The GC is adept at reclaiming the memory occupied by managed objects. However, you should follow certain guidelines to facilitate faster garbage collection so as to improve your application's performance.

Should I use the GC.Collect() method?

First off, do you at all need to call GC.Collect in your application’s code? The answer in most cases is no. Let me now tell you what this method does and why you should refrain from calling this method in most cases.

When you make a call to GC.Collect() method, the runtime performs a stack walk to determine the objects that are reachable and those that aren't. It also freezes the main thread (and also any child threads it created) of the application. In other words, when the GC.Collect() method is called, the runtime performs a blocking garbage collection of all generations.

I would always prefer not to use GC.Collect() unless there is a specific reason to use it. A GC typically consists of the Mark and Sweep phases followed by a Compaction phase. The time spent by the runtime to perform a GC may become a bottleneck, so, use it only very rarely and if you really need to. Rico Mariani states: "Consider calling GC.Collect() if some non-recurring event has just happened and this event is highly likely to have caused a lot of old objects to die."

Using the GC.Collect() method

Here's how you can invoke the GC.Collect() method in your code.

GC.Collect();

Note that you can also collect objects that pertain to a specific generation.

GC.Collect() – used to collect objects present in the generations 0, 1, 2

GC.Collect(0) – used to collect objects present in generation 0

GC.Collect(1) – used to collect objects present in generations 0 and 1

You can also determine how much memory has been freed by making a call to the GC.Collect() method. To do this, you can take advantage of the System.GC.GetTotalMemory() method as shown in the code snippet below.

//Write code to create some large objects here

Console.WriteLine("Total available memory before collection: {0:N0}", System.GC.GetTotalMemory(false));

System.GC.Collect();

Console.WriteLine("Total available memory collection: {0:N0}", System.GC.GetTotalMemory(true));

The GC.GetGeneration() method can be used to know the generation to which an object belongs. Refer to the code listing given below.

static void Main(string[] args)

       {

           List<string> obj = new List<string>() { "Joydip", "Steve" };

           Console.WriteLine(System.GC.GetGeneration(obj));

           System.GC.Collect();

           Console.WriteLine(System.GC.GetGeneration(obj));

           System.GC.Collect();

           Console.WriteLine(System.GC.GetGeneration(obj));

           Console.Read();

       }

When you execute the above program, here's what is printed in the console window.

0

1

2

As you can see, each call to the GC.Collect() method promotes the object "obj" to the next higher generation. This is because the object "obj" survives the garbage collection in each of the two cases, i.e., it is not reclaimed in any of the two calls made to the GC.Collect() method.

You can force garbage collection either to all the three generations or to a specific generation using the GC.Collect() method. The GC.Collect() method is overloaded -- you can call it without any parameters or even by passing the generation number you would like to the garbage collector to collect.

Note that objects that have finalizers (and if a call to SuppressFinalize method hasn’t been made) would not be collected when a call to GC.Collect() method is made. Rather, such objects would be placed in the finalization queue. If you would like to collect those objects as well, you would need to make a call to the GC.WaitForPendingFinalizers() method so that those objects are cleaned up when the next GC cycle runs. In essence, reclaiming the memory occupied by objects that have finalizers implemented requires two passes since such objects are placed in the finalization queue rather than being reclaimed in the first pass when the garbage collector runs.

This article is published as part of the IDG Contributor Network. Want to Join?

To comment on this article and other InfoWorld content, visit InfoWorld's LinkedIn page, Facebook page and Twitter stream.
From CIO: 8 Free Online Courses to Grow Your Tech Skills
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.