A Deep Dive into the GC.Collect Method in .NET

While the GC.Collect method is invoked implicitly by the runtime, there are certain situations when a developer might also need to invoke the GC.Collect method explicitly. In this .NET programming tutorial, we will take a deep dive into the GC.Collect method and try to understand how it works and when programmers should use it.

Looking to learn how to create software using .NET in a course or classroom environment? We have a listing of the Best Online Courses for .NET Developers that will help you get started.

Managed and Unmanaged Objects in .NET

In .NET, objects are either created in the managed heap or the unmanaged heap, depending on whether the object is a managed or an unmanaged one. While the managed objects are destroyed by the CLR (Common Language Runtime) implicitly, the unmanaged objects are not.

Developers working on .NET often use the GC.Collect () method to force a garbage collection to clean up memory occupied by managed objects. The CLR takes advantage of garbage collection to release resources used by your application.

Note that a call to the GC.Collect never cleans memory occupied by unmanaged objects. The runtime is adept at destroying objects residing in the managed heap when you no longer need them. However, if a developer has created unmanaged objects in their application, they must clean them explicitly.

Read: C# Tools for Code Quality

When Should You Call the GC.Collect Method?

The CLR organizes the managed heap into Generation 0, Generation 1, and Generation 2. It should be noted that .NET objects are created in the managed heap and automatically deleted by the runtime when they are no longer in use.

The GC.Collect method is not guaranteed to free all unused objects from memory that are no longer referenced by your application. Objects that are still in use by your application will not be collected.

In general, programmers should only call the GC.Collect method if they are sure their application no longer uses any objects that the garbage collector previously collected. The GC.Collect method is a blocking call, meaning your application will pause while the garbage collector is running.

This can cause your application to be unresponsive. For this reason, you should only call the GC.Collect method when necessary – calling the GC.Collect method too often can degrade the performance of your application.

This is because the garbage collector will have to run more often, which takes up valuable resources. When you call the GC.Collect method, the runtime will attempt to force clean objects residing in all generations.

Moreover, a call to GC.Collect will block your application’s threads until the GC.Collect method has completed its execution. In other words, since the GC.Collect method is a blocking call, your application will pause while the garbage collector is running.

GC Runs as a Low-priority Background Thread in .NET

The GC runs as a low-priority background thread, so it does not interfere with your application’s performance. You can also explicitly call the GC.Collect method to force a garbage collection, but this is generally not necessary. The GC is designed to be very efficient, so it will only run when absolutely necessary. This means that your application’s performance should not be adversely affected by the GC.

The GC will start running when it detects that there are enough unused objects to make it worthwhile. It will then continue to run until it has cleaned up all the unused objects.

Nevertheless, there are situations where garbage collection might benefit performance. For example, if your application allocates a lot of memory upfront and then no longer requires it, later on, you might want to call the GC.Collect method to clean up the unused memory sooner rather than later.

You should only force a garbage collection if you have a specific reason. Note that the GC is designed to be very efficient, so there’s no need to try and second-guess it. One final thing to note about the GC is that it only cleans up managed objects.

This means that if your application allocates memory directly from the operating system (for example, using the Win32 API), the GC will not clean it up; you will need to explicitly free this memory yourself when you are finished with it.

Why Does GC.Collect Method Need to be Called Explicitly in .NET?

When you use the GC.Collect() method, the CLR walks the stack to identify which items are accessible and which are not. It also freezes the application’s main thread and any child threads along with it. In other words, the runtime conducts a blocking garbage collection of all generations when the GC.Collect() function is invoked.

A good practice is not to use this method at all unless there is a particular reason to use it. Typically, the Mark and Sweep phases are followed by the compaction phase in a GC. The time required by the runtime to complete a GC may create a bottleneck; therefore, utilize it sparingly and only when necessary.

Read: Productivity Tools for .NET Developers

How to Program the GC.Collect Method in .NET

As mentioned previously, the managed heap is split into three generations by the CLR: Generation 0, Generation 1, and Generation 2. Note that the GC.Collect method is overloaded. Here are the overloads of the GC.Collect method:

  • GC.Collect() – this method can be used to collect objects residing in all the generations (i.e., Generation 0, 1, and 2)
  • GC.Collect(0) – this method can be used to collect objects present in Generation 0
  • GC.Collect(1) – this method can be used to collect objects present in Generations 0 and 1

If an object cannot be garbage collected, every call to the GC.Collect method promotes an object to the next higher generation. The following code snippet illustrates how you can verify this in .NET:

List obj = new List() { "ABC", "XYZ" };
for(int i = 0; i < 2; i++)
{
    Console.WriteLine("The object obj is now in generation: {0}", 
    System.GC.GetGeneration(obj));
    System.GC.Collect();
}
Console.WriteLine("The object obj is now in generation: {0}", System.GC.GetGeneration(obj));

Figure 1 below illustrates the output when you execute the above code:

GC Collect Method in .NET

Final Thoughts on the GC.Collect Method in .NET

If there are too many objects in Generation 0 or 1 then this will slow down collection times significantly – which may make your app seem unresponsive while the collections occur. You can collect specific generations with the GC.Collect method by calling it with the number of generations you want to collect. You can pass in 0, 1, or 2 to specify which generation you want to collect.

In most cases, programmers will not need to worry about when the GC will be called implicitly – the runtime will take care of it in the background. However, there are some situations where you might need to force a garbage collection, or take care of unmanaged memory allocations.

Note that the GC only cleans up managed objects. This means that if your application allocates memory directly from the operating system (for example, using the Win32 API), the GC will not clean it up; developers will need to explicitly free this memory themselves when they are finished with it.

Read more .NET programming tutorials and software development guides.

Joydip Kanjilal
Joydip Kanjilal
A Microsoft Most Valuable Professional in ASP.NET, Speaker, and Author of several books and articles. More than 25 years of experience in IT with more than 18 years in Microsoft .NET and its related technologies. He was selected as a Community Credit Winner at http://www.community-credit.com several times. He has authored 8 books and more than 500 articles in some of the most reputed sites worldwide including MSDN, Info World, CodeMag, Tech Beacon, Tech Target, Developer, CodeGuru, and more.

More by Author

Must Read