How to Force Garbage Collection in C#

Muhammad Maisam Abbas Feb 15, 2024
  1. Understanding Garbage Collection in C#
  2. C# Force Garbage Collection With the GC.Collect() Method
  3. Using GC.Collect() With GC.WaitForPendingFinalizers
  4. Using GC.Collect With Generation Parameter
  5. Using GC.TryStartNoGCRegion and GC.EndNoGCRegion
  6. Conclusion
How to Force Garbage Collection in C#

Garbage collection is a critical aspect of memory management in C#. While the .NET runtime automatically handles memory cleanup, there are scenarios where you might want to force garbage collection explicitly.

In this article, we will delve into different methods to trigger garbage collection in C#, providing detailed examples and explanations for each approach.

Understanding Garbage Collection in C#

It’s crucial to understand the basics of garbage collection in C#. The .NET runtime utilizes a garbage collector to automatically identify and collect objects that are no longer in use, freeing up memory and resources.

Objects in .NET are allocated on the managed heap, and when an object is no longer reachable from the root of the object graph (such as local variables, static variables, etc.), it becomes eligible for garbage collection. The garbage collector then identifies and reclaims the memory occupied by these unused objects.

However, objects with finalizers require special consideration. Finalizers are special methods (destructors) that are executed before an object is garbage-collected. Finalizers are typically used for cleanup tasks, such as releasing unmanaged resources.

C# Force Garbage Collection With the GC.Collect() Method

The GC.Collect method is the most direct way to request garbage collection in C#. However, it’s essential to use it judiciously, as forcing collection too frequently can impact performance.

The GC.Collect() method in C# carries out forced garbage collection. The GC.Collect() method reclaims all the inaccessible memory.

With this method, all objects that are in memory are considered for cleaning. However, the objects referenced in a managed piece of code are not considered for cleaning.

The GC.Collect method is part of the System namespace and is responsible for triggering garbage collection. Calling this method suggests to the runtime that it’s an appropriate time to collect unused objects.

Note that the runtime might choose not to collect immediately, as it optimizes garbage collection for performance.

using System;

namespace randomize_array {
  class Program {
    static void Main(string[] args) {
      int[] i = new int[100000];
      GC.Collect();
    }
  }
}

In the above code, we first generated some unused garbage in the memory with the int[] i = new int[100000] line and then forced the garbage collector to collect the garbage and free up all the memory with the GC.Collect() method.

Using GC.Collect() With GC.WaitForPendingFinalizers

In situations where you want to ensure that finalizers (destructors) for objects are executed before garbage collection completes, you can use GC.WaitForPendingFinalizers in conjunction with GC.Collect.

// Using GC.WaitForPendingFinalizers along with GC.Collect
GC.Collect();
GC.WaitForPendingFinalizers();

Objects with finalizers are not immediately collected; instead, they go through a two-step process. The GC.Collect call initiates garbage collection, and GC.WaitForPendingFinalizers ensures that the finalizers for objects are executed before moving on.

Using GC.Collect With Generation Parameter

The garbage collection mechanism in .NET is generational, dividing objects into three generations based on their age. These generations are:

  1. Generation 0: Newly created objects are placed in Generation 0.
  2. Generation 1: Objects that survive a garbage collection cycle in Generation 0 are promoted to Generation 1.
  3. Generation 2: Objects that survive in Generation 1 are promoted to Generation 2. Garbage collection in Generation 2 occurs less frequently.

Generational garbage collection is efficient because most objects are short-lived, and collecting Generation 0 is faster than collecting the entire heap.

The GC.Collect method is a tool provided by the .NET runtime to explicitly trigger garbage collection. When used with a generation parameter, it allows developers to target a specific generation for collection.

// Using GC.Collect with a specific generation
GC.Collect(2, GCCollectionMode.Forced, true);

In this example, GC.Collect is called with parameters specifying the generation (in this case, generation 2), the collection mode (forced), and whether to block the calling thread until the garbage collection is complete (true).

Using GC.TryStartNoGCRegion and GC.EndNoGCRegion

Garbage collection regions are designated sections of code where developers can control the garbage collection process. GC.TryStartNoGCRegion and GC.EndNoGCRegion allow developers to create a region where garbage collection is either disallowed or allowed but with specific constraints.

If you want to prevent garbage collection for a specific region of code, you can use GC.TryStartNoGCRegion and GC.EndNoGCRegion. This is an advanced method that should be used with caution.

Let’s explore a scenario where these methods can be beneficial. Consider an application that performs time-sensitive calculations and wants to avoid garbage collection during critical sections of code.

// Using GC.TryStartNoGCRegion and GC.EndNoGCRegion
public static void Main() {
  // Perform some time-sensitive calculations...

  // Start a no-GC region
  bool succeeded = GC.TryStartNoGCRegion(1000000);
  if (succeeded) {
    try {
      // Code without garbage collection
      // Perform critical operations...
    } finally {
      // End the no-GC region
      GC.EndNoGCRegion();
    }
  }

  // Continue with program execution...
}

In this example, the GC.TryStartNoGCRegion method is called with a specified size for the no-GC region. If successful, a try-finally block is used to enclose the critical section of code, ensuring that GC.EndNoGCRegion is called to end the no-GC region.

This way, garbage collection is temporarily disabled, allowing critical operations to proceed without interruption.

Conclusion

Forcing garbage collection in C# should be approached with caution, as the runtime is optimized to handle memory efficiently. In most scenarios, allowing the automatic garbage collector to do its job is sufficient.

However, understanding the various methods available for explicit garbage collection provides developers with tools to address specific performance or resource management requirements. Choose the method that best fits your needs, and always consider the potential impact on performance and application behavior.

Muhammad Maisam Abbas avatar Muhammad Maisam Abbas avatar

Maisam is a highly skilled and motivated Data Scientist. He has over 4 years of experience with Python programming language. He loves solving complex problems and sharing his results on the internet.

LinkedIn