한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

Game Lag White Paper › L10 Memory

Server GC stop-the-world pause Stop-the-world GC pause

Cause ID mem-gc · Primary owner Game team (Server development) · Also Infra team (Server infrastructure)

Open the interactive card with figures and simulations →

While a Java or C# server halts every thread to collect garbage (stop-the-world), the whole server stalls.

Why The heap fills up and GC starts → Effect Every game thread stops while GC collects (longer the more live data there is) → On screen Everyone on the server freezes at the same moment, then the game fast-forwards

Symptoms
Freeze, Fast-forward
Factors
Stall
Who’s affected
Whole server
When
At regular intervals, The longer it runs
Owner
Primary owner Game team (Server development) · Also Infra team (Server infrastructure)
Game team action items
Explicitly select a low-pause GC (ZGC, Shenandoah, or G1 with a lower pause target) in the launch options, reduce allocations, tune heap size.
Infra team action items
Use instances with enough memory for a generous heap, give containers at least 2 CPUs and about 1.8 GB of memory (with less, JDK 26 and earlier pick Serial GC by default), monitor GC pause times.
Ballpark numbers
A minor GC that collects only new objects (the young generation) takes a few to tens of milliseconds. A full GC over a whole heap holding several GB of live data can take over 1 second. ZGC stays under 1 ms almost regardless of heap size, and Shenandoah pauses are also short because they don’t grow with heap size.
On the graph
Periodic spikes · Server tick time, GC pause time
Where to look
Turn on GC logging and overlay pause times and lengths on the server tick-time graph. Java: Pause lines from the startup option -Xlog:gc* (-XX:+PrintGCDetails on JDK 8 and earlier). .NET: the GC pause metric in dotnet-counters (dotnet.gc.pause.time on .NET 9 and later, % Time in GC since last GC on 8 and earlier). Go: the line GODEBUG=gctrace=1 writes for each GC
Confirmed if
Tick spikes line up with GC pauses, and pause length matches spike length. Every zone and channel on the server spikes at the same moment
Ruled out if
Ticks spike with no long pauses in the GC log: another cause such as locks, blocking calls, or disk writes. Only one zone spikes: the script engine’s GC (mem-script-gc) or that zone’s load
Check with
Infra tools (no game code needed)
Learn more
Java’s G1 has a default target of 200 ms per pause, which is 4 ticks on a 20-tick server. If a container gets fewer than 2 CPUs or less than about 1.8 GB of memory, Java on JDK 26 and earlier picks Serial GC, which collects on a single thread, as the default GC, and pauses get much longer. C# (.NET) servers usually turn on server GC and background GC, but collections of generations 0 and 1 (Gen0/1), where new objects live, and full GCs with compaction still stop every thread. Go pauses are usually under 1 ms, but under heavy allocation the code requesting memory has to take on part of the GC work, so ticks slow down. With any GC, if allocation outpaces collection, the game thread eventually stops. G1 falls back to a full GC, and ZGC stalls the thread requesting memory until the collection finishes.
Real incidents
Riot Games 2021: League of Legends EUW 5-hour outage: one auxiliary DB halted the whole server

Sources

  1. Garbage-First (G1) Garbage Collector Oracle
    G1 default pause target 200 ms (MaxGCPauseMillis); if memory runs out during collection, it falls back to a full GC that stops and compacts the whole heap
  2. JEP 523: Make G1 the Default Garbage Collector in All Environments OpenJDK
    Previously, Serial GC was the default with 1 CPU or less than 1792 MB of memory; from JDK 27, G1 is the default everywhere
  3. JEP 439: Generational ZGC OpenJDK
    ZGC pauses are 1 ms or less regardless of heap size; G1 pauses range from a few ms to a few seconds. Risk of allocation stalls when allocation outpaces reclamation
  4. JEP 189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental) OpenJDK
    Shenandoah pause times are about the same whether the heap is 200 MB or 200 GB
  5. Background garbage collection .NET
    Background GC applies only to gen2 collections; gen0 and gen1 collections (foreground GC) stop all managed threads
  6. A Guide to the Go Garbage Collector Go
    Go’s GC runs mostly concurrently with only short stop-the-world pauses; under heavy allocation, goroutines take on GC work (assist), which adds latency
  7. JEP 271: Unified GC Logging OpenJDK
    JDK 9 reimplemented GC logging on unified logging (-Xlog); -Xlog:gc writes one line per GC, like the old -XX:+PrintGC
  8. The java Command Oracle
    Table mapping old GC log options to -Xlog: -XX:+PrintGCDetails becomes -Xlog:gc*
  9. dotnet-counters diagnostic tool .NET
    .NET 9 and later show System.Runtime meters (dotnet.gc.pause.time and others); .NET 8 and earlier show the older EventCounters (% Time in GC since last GC and others)
  10. runtime package Go
    GODEBUG=gctrace=1: one line per GC with wall-clock time per phase, heap size at GC start and end, and the heap goal

See also

Same layer: L10 Memory

Same symptom (Freeze), other layers

View the interactive card with figures and simulations