GC Server Mode - Eonic/ProteanCMS GitHub Wiki

Server GC Mode Configuration

Overview

Server GC Mode is a Garbage Collection optimization for .NET applications running on multi-core systems. It significantly improves throughput and reduces GC pause times for web applications like ProteanCMS by enabling parallel garbage collection across all CPU cores.


What is Server GC Mode?

Server GC creates one dedicated garbage collection thread per CPU core, enabling parallel collection across all available processors. This contrasts with Workstation GC, which uses a single thread for garbage collection.

Workstation GC vs Server GC

Aspect Workstation GC (Default) Server GC
Best For Desktop applications, client apps Web servers, high-throughput applications
GC Threads Single thread One thread per CPU core
Memory Usage Lower (~30 MB per heap) Higher (~120 MB on 4-core system)
GC Pause Time 50-100ms typical 10-20ms typical
Throughput Lower 2-3x higher
CPU Utilization Single core during GC All cores during GC
Heap Structure Single heap Separate heap per CPU core

How Server GC Works

1. Heap Segmentation

Server GC creates separate heaps per CPU core:

CPU 1: Heap A β†’ Gen0 | Gen1 | Gen2 CPU 2: Heap B β†’ Gen0 | Gen1 | Gen2 CPU 3: Heap C β†’ Gen0 | Gen1 | Gen2 CPU 4: Heap D β†’ Gen0 | Gen1 | Gen2

2. Parallel Collection

When garbage collection is triggered, all heaps are collected simultaneously:

Thread 1 β†’ Collects Heap A ┐ Thread 2 β†’ Collects Heap B β”œβ”€ All at once Thread 3 β†’ Collects Heap C β”‚ Thread 4 β†’ Collects Heap D β”˜

3. Reduced Lock Contention

Each request thread allocates on its own heap, eliminating lock contention:

Request Thread 1 β†’ Allocates on Heap A ┐ Request Thread 2 β†’ Allocates on Heap B β”œβ”€ No locking needed Request Thread 3 β†’ Allocates on Heap C β”‚ Request Thread 4 β†’ Allocates on Heap D β”˜


Performance Benefits for ProteanCMS

Expected Improvements

Metric Before Server GC After Server GC Improvement
Requests/sec 50-100 150-300 2-3x increase
Response Time 200ms avg 100ms avg 50% faster
GC Pause Time 50-100ms 10-20ms 5x reduction
Gen2 Collections 10/min 3/min 70% fewer
Memory Usage 500 MB 700 MB +40% (acceptable)

Why Server GC Benefits ProteanCMS

ProteanCMS performs memory-intensive operations that benefit from parallel GC:

  • Large XML Documents: moPageXml processing
  • XSLT Transformations: moTransform operations
  • Cart Operations: Multiple object allocations
  • Content Detail XML: Generation and manipulation
  • Menu Structure: Building and caching

Example Performance Impact:

// Before (Workstation GC): GetPageHTML() { moPageXml = new XmlDocument(); // Allocates memory BuildPageXML(); // More allocations Transform(moPageXml, moResponse); // Even more! // [GC Pause: 50-100ms] ⏸️ } // After (Server GC): GetPageHTML() { moPageXml = new XmlDocument(); // Allocates on CPU-specific heap BuildPageXML(); // Fast parallel collection Transform(moPageXml, moResponse); // Minimal pause! // [GC Pause: 10-20ms] ⚑ }


Configuration

Web.config Settings

Add the following configuration to the <runtime> section of your Web.config:

Configuration Options

Setting Values Description
gcServer true/false Enables/disables Server GC mode
gcConcurrent true/false Enables concurrent GC (reduces pause times)
gcAllowVeryLargeObjects true/false Allows objects > 2GB (rarely needed)

Memory Trade-offs

Memory Overhead

Server GC uses approximately 3-4x more memory for heap management:

  • Workstation GC: ~30 MB heap overhead (single heap)
  • Server GC (4 cores): ~120 MB heap overhead (4 heaps)

Visual Comparison

Workstation GC: β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Gen0: 4 MB β”‚ β”‚ Gen1: 8 MB β”‚ β”‚ Gen2: 16 MB β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Total: ~30 MB Server GC (4 cores): β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ CPU1 Gen0: 4 MB β”‚ β”‚ CPU1 Gen1: 8 MB β”‚ β”‚ CPU1 Gen2: 16 MB β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ CPU2 Gen0: 4 MB β”‚ β”‚ CPU2 Gen1: 8 MB β”‚ β”‚ CPU2 Gen2: 16 MB β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ CPU3 Gen0: 4 MB β”‚ β”‚ CPU3 Gen1: 8 MB β”‚ β”‚ CPU3 Gen2: 16 MB β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ CPU4 Gen0: 4 MB β”‚ β”‚ CPU4 Gen1: 8 MB β”‚ β”‚ CPU4 Gen2: 16 MB β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Total: ~120 MB

Why This Trade-off Is Acceptable

  1. Modern servers typically have 8+ GB RAM
  2. Performance gains far outweigh memory cost
  3. Better throughput means fewer servers needed
  4. Reduced GC pause time improves user experience
  5. Combined with IDisposable pattern, net memory usage is still optimal

Verification and Monitoring

Verify Server GC is Active

Add this code to Global.asax.cs or application startup:

protected void Application_Start() { // Check GC mode string gcMode = GCSettings.IsServerGC ? "Server" : "Workstation"; System.Diagnostics.Trace.WriteLine($"GC Mode: {gcMode}"); // Log additional GC info System.Diagnostics.Trace.WriteLine($"CPU Count: {Environment.ProcessorCount}"); System.Diagnostics.Trace.WriteLine($"GC Latency Mode: {GCSettings.LatencyMode}");

// Expected output: "GC Mode: Server" }

Monitor GC Performance

Use Performance Counters to track GC metrics:

using System.Diagnostics; // Setup performance counters PerformanceCounter gcGen0 = new PerformanceCounter( ".NET CLR Memory", "# Gen 0 Collections", Process.GetCurrentProcess().ProcessName); PerformanceCounter gcGen1 = new PerformanceCounter( ".NET CLR Memory", "# Gen 1 Collections", Process.GetCurrentProcess().ProcessName); PerformanceCounter gcGen2 = new PerformanceCounter( ".NET CLR Memory", "# Gen 2 Collections", Process.GetCurrentProcess().ProcessName); PerformanceCounter gcTimePercent = new PerformanceCounter( ".NET CLR Memory", "% Time in GC", Process.GetCurrentProcess().ProcessName); // Log periodically (e.g., every 10 seconds) System.Diagnostics.Debug.WriteLine( $"GC Stats - Gen0: {gcGen0.NextValue()}, " + $"Gen1: {gcGen1.NextValue()}, " + $"Gen2: {gcGen2.NextValue()}, " + $"Time in GC: {gcTimePercent.NextValue()}%");

Key Performance Metrics

Metric What to Monitor Expected Change
Gen 0 Collections Frequency of Gen0 GC May increase slightly
Gen 1 Collections Frequency of Gen1 GC Should remain stable
Gen 2 Collections Frequency of Gen2 GC Should decrease significantly
% Time in GC CPU time spent in GC Should decrease dramatically
Allocated Bytes/sec Memory allocation rate May increase slightly

When to Use Server GC

βœ… Use Server GC When:

  • Running on multi-core servers (2+ cores)
  • Using dedicated hosting or VPS
  • Building high-throughput web applications
  • Processing large objects (XML, DataSets, Images)
  • Handling concurrent requests
  • Memory is not severely constrained (4+ GB available)
  • Running ASP.NET web applications (like ProteanCMS)

❌ Avoid Server GC When:

  • Running on single-core machines
  • Severely memory-constrained (< 2 GB RAM)
  • Running desktop applications with UI responsiveness requirements
  • Using shared hosting with strict memory limits
  • Running console applications with short lifetimes
  • Client-side applications where latency is more critical than throughput

⚠️ **GitHub.com Fallback** ⚠️