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

Game Lag White Paper › L1 Client game process

Client garbage collection Client GC (Unity C#, Unreal, Lua)

Cause ID cg-gc · Primary owner Game team (Client development)

Open the interactive card with figures and simulations →

The whole game freezes while it reclaims memory that was used and thrown away (garbage). The telltale sign is stutter at regular intervals.

Why Temporary strings, arrays, and lists are created and thrown away every frame → Effect Once garbage piles up, GC pauses the main thread to reclaim it → On screen Regular stutter every few seconds to tens of seconds

Symptoms
Stutter, Freeze
Factors
Stall
Who’s affected
Just me
When
At regular intervals, When crowds gather
Owner
Primary owner Game team (Client development)
Game team action items
Reduce allocations (avoid string concatenation, LINQ, and lambda captures), use object pools, keep incremental GC on (the default since Unity 2020), run GC ahead of time when a pause does no harm, such as on a loading screen.
Ballpark numbers
Usually a few ms to 100 ms per pause, longer on low-end phones or in games that use a lot of memory (about 150–170 ms in the simulation). Unity’s GC scans the whole heap every time it runs, so the more memory the game is using, the longer it takes.
On the graph
Periodic spikes · Frame time, GC run times
Where to look
In a development build, check the GC.Collect and GC.Alloc markers in the Unity Profiler. In Unreal, stat GC and stat Hitches (logs frames longer than the threshold set by t.HitchFrameTimeThreshold)
Confirmed if
Every spiking frame contains a GC.Collect section about as long as the spike, at regular intervals of a few seconds to tens of seconds. GC.Alloc per frame rises in crowded places
Ruled out if
No GC section in the spiking frames: “Synchronous loading and shader compilation on the main thread” or “Rendering load from large crowds”
Check with
Game server or client logs and metrics
Learn more
Common in clients that use C#, such as Unity. The usual culprit is code that builds combat log strings, damage numbers, and UI text from scratch every frame. If it only stutters in crowded places, some code is producing garbage in proportion to the player count. Incremental GC collects a little at a time in each frame (3 ms by default in Unity), but if the game makes garbage faster than it collects, it still ends up pausing all at once. Unreal Engine also has its own GC that cleans up unused game objects. It depends on the engine version and settings, but with default settings it runs about once a minute and can cause a hitch every minute. Clients that write game rules in a scripting language such as Lua also run that script’s GC separately.

Sources

  1. Garbage collection modes Unity
    Incremental GC is the default and collects across several frames; with it off, the main thread stops while the whole heap is scanned, which can take up to hundreds of ms
  2. Scripting.GarbageCollector.CollectIncremental Unity
    The default target for the time incremental GC spends per run (time slice) is 3 ms (incrementalTimeSliceNanoseconds)
  3. Garbage Collection Settings in the Unreal Engine Project Settings Epic Games
    The setting that makes Unreal’s GC run at a fixed interval (Time Between Purging Pending Kill Objects, in seconds). This page doesn’t give the default value
  4. Profiler markers reference Unity
    GC.Collect: time program code is paused during garbage collection (under 1 ms to hundreds of ms); GC.Alloc: managed heap allocations
  5. Stat Commands in Unreal Engine Epic Games
    stat GC (garbage collection statistics), stat Hitches (logs frames that exceed t.HitchFrameTimeThreshold)

See also

Same layer: L1 Client game process

Same symptom (Stutter), other layers

View the interactive card with figures and simulations