Microsoft Docs

Garbage Collection in .NET Core

Garbage collection (GC) is the process by which the .NET Core runtime automatically manages memory. It reclaims memory that is no longer being used by an application, preventing memory leaks and simplifying memory management for developers. Understanding how GC works is crucial for writing efficient and stable .NET Core applications.

How Garbage Collection Works

The .NET Core garbage collector is a generational, compacting garbage collector. This means it:

The Managed Heap and Generations

The managed heap is where all objects allocated by the .NET Core runtime are stored. The GC divides the heap into three primary generations:

The GC Algorithm

When a garbage collection occurs, the GC performs the following steps:

  1. Marking: The GC starts from the root objects (e.g., static fields, local variables on the stack, CPU registers) and traverses the object graph to find all reachable objects. Any object that can be reached from a root is considered "live."
  2. Relocation (Compacting): For a compacting GC, the live objects are moved to fill the gaps left by the dead objects. This process also updates references to the moved objects.
  3. Sweeping (or Freeing): The memory occupied by unreachable objects (which are now marked as dead) is reclaimed and made available for new allocations.

GC Modes

.NET Core supports two main GC modes:

Workstation GC

Optimized for client applications, such as desktop applications. It prioritizes low latency by running on fewer CPU cores, minimizing pauses. The Workstation GC can be configured in Server GC or Non-server GC modes. The default is Non-server GC.

  • Non-server GC: Runs on a single background thread, minimizing pauses. Suitable for applications where responsiveness is critical.
  • Server GC: Uses multiple background threads to perform collections concurrently on multiple CPU cores. This improves throughput by reducing the overall GC time, but may introduce slightly longer pauses. Recommended for server-side applications.

Server GC

Optimized for server applications. It aims to maximize throughput by using multiple GC threads that run on different CPU cores simultaneously. This leads to faster collections overall but can result in slightly longer pauses compared to Workstation GC.

Configuring GC Behavior

You can influence GC behavior through configuration settings:

Runtime Configuration

You can set GC modes using environment variables or a runtimeconfig.json file.

Environment Variable:

COMPlus_GCServer=1

Setting COMPlus_GCServer to 1 enables Server GC. Setting it to 0 (or not setting it) enables Workstation GC.

runtimeconfig.json:


{
  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  }
}
            

Setting System.GC.Server to true enables Server GC.

GC Latency Mode

You can also control the GC's aggressiveness using the System.GC.LatencyMode property:

Configuration example:


{
  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": false, // Workstation GC
      "System.GC.LatencyMode": "Interactive"
    }
  }
}
            

Best Practices for GC Performance

Note: In most scenarios, the default GC settings provide excellent performance. Only tune GC parameters if you have profiled your application and identified memory management as a bottleneck.

Further Reading