Memory Insights & Low-Level Memory Tracker
You need three tools to triage UE5 memory: memreport for a UObject-centric snapshot, LLM (Low-Level Memory Tracker) for an OS-allocation-centric continuous view, and Memory Insights to stitch both onto a timeline. Per Epic engineer Sebastian Thomeczek, untracked memory in Insights is allocator overhead and driver bytes Insights cannot see — the gap between process RSS and Insights total is real and important. This tutorial walks the senior workflow.
Why three tools, not one
Each tool answers a different question:
memreport— UObject-centric snapshot. "What objects are loaded right now and how big are they?"- LLM — OS-allocation-centric continuous view, tagged by subsystem. "Where is my heap going by category?"
- Memory Insights — timeline + callstack of every allocation. "What allocated this byte and when?"
Senior devs need all three because allocator overhead, driver memory, and untracked LLM bytes diverge from process RSS — and you can't tell which from any single tool.
Capturing a Memory Insights trace
YourGame.exe ^
-trace=default,memory,callstack,module,memalloc,memtag,metadata,assetmetadata,bookmark ^
-statnamedevents
memalloc must be on at process start
You cannot toggle it later via Trace.Start. Forgetting this produces an empty Memory tab with timing data still showing — the most common Memory Insights trap.
The memalloc channel is heavy — expect ~10–20% perf overhead during capture. Use Development/DebugGame builds, not Shipping. LLM is compiled out of Test/Shipping by default unless ENABLE_LOW_LEVEL_MEM_TRACKER=1 is force-defined.
Reading the Memory Insights timeline
Four panels that matter:
- Timing — main timeline.
- Investigation — A/B markers and query rules.
- LLM Tags — per-tag totals over time.
- Modules — allocations by code module.
Three numbers to know: LLM Total, LLM TrackedTotal, LLM Untracked. Per Epic's Sebastian Thomeczek, untracked = allocator overhead + driver bytes Insights cannot see. A growing Untracked over time is a smell, not necessarily a leak.
The Investigation panel as a leak hunter
The leak-hunting workflow:
- Drag A/B markers on the timeline around the suspected leak window (e.g., "before level load A → after level B").
- Pick a query rule: live-at-B-but-not-at-A, long-living, short-lived-leaked.
- Run Query.
- Sort the Alloc table by Size or LLM Tag.
- Double-click into the callstack — that's your leak source.
Iteration: bookmark with TRACE_BOOKMARK(TEXT("PreLoad")) → obj gc → TRACE_BOOKMARK(TEXT("PostUnload")) around the suspect transition. Three load/unload cycles; query between matched bookmarks; any tag still growing across cycles is the leak.
LLM — stat llm & stat llmfull
LLM exposes two trackers (Default and Platform), each with its own tag stack. Run with -llm at launch (Development/DebugGame; not Shipping by default), then:
stat llm— live, grouped tag totals on screen.stat llmfull— every tag, including platform-specific ones (RHIMisc,Audio,Mesh,Texture,Animation,Physics,Niagara,EngineMisc,UObject,AssetRegistry).-llmcsvwrites CSV per-tracker intoSaved/Profiling/llm/, one column per tag, MB values, ~5s cadence. Diff CSVs across builds for tag-level regression detection.
Custom LLM tags for game code
// Header LLM_DECLARE_TAG(MyGame_AI); // .cpp LLM_DEFINE_TAG(MyGame_AI); // Wrap allocations { LLM_SCOPE_BYTAG(MyGame_AI); AICachedData.Reserve(LargeNumber); // or LLM_SCOPE(ELLMTag::Foo) for built-in tags }
Custom tags appear in both stat llmfull and the Memory Insights LLM Tags panel without engine modification. Add tags around any subsystem you ship more than ~5 MB through — AI caches, replay buffers, custom asset systems, networking subobject pools.
memreport deep dive
Trigger memreport -full in PIE or via gameplay command. File lands in <Project>/Saved/Profiling/MemReports/, named with map + timestamp. Walk the canonical sections:
- Platform memory header — OS-side numbers.
obj list -alphasort—NumKBytes(UObject body) andExclusiveResKBytes(owned resources).rhi.DumpMemory— GPU-side resources.ListTextures,ListSounds,r.DumpRenderTargetPoolMemory— per-asset-class.
BaseEngine.ini has [MemReportCommands] and [MemReportFullCommands] sections that you can extend with project-specific dumps. Add anything subsystem-specific you want to track.
GC bookmarks for leak repro
The deterministic leak-repro pattern:
TRACE_BOOKMARK(TEXT("PreLoad_Cycle1")); LoadLevel(TEXT("TestLevel")); ProcessAsyncLoading(); TRACE_BOOKMARK(TEXT("PostLoad_Cycle1")); UnloadLevel(TEXT("TestLevel")); GEngine->ForceGarbageCollection(true); TRACE_BOOKMARK(TEXT("PostUnload_Cycle1")); // Repeat for cycles 2 and 3
After three cycles, run an Investigation query between matched bookmarks (e.g., PostUnload_Cycle1 vs PostUnload_Cycle3). Any tag still growing across cycles is the leak. Pair with obj gc or gc.CollectGarbageEveryFrame 1 for aggressive GC pressure.
UE 5.6 asset-class memory profiling
UE 5.6 added experimental LLM TagSets — System, AssetClass, Asset — with per-platform memory budgets per asset type (per Tom Looman's 5.6 highlights). Switch trackers via au.MetaSound.Pages.SetTarget-equivalent CVars or via the LLM TagSet config.
Workflow: enable asset memory tracing, switch the LLM TagSet to AssetClass, set per-platform budgets per asset type. Out-of-budget rows light up automatically in Insights.
This is the closest UE5 has gotten to "automatic per-asset-type budget enforcement" — useful but still experimental in 5.6.
Senior workflow checklist
- Repro the symptom. OOM crash? Streaming pool warning? Slow growth?
- Bookmark. Surround the suspect window with
TRACE_BOOKMARK. - Capture trace with the
memallocchannel on at process start. - Diff via Investigation panel. A/B between matched bookmarks.
- Confirm with
memreport -full. Two snapshots, diff side-by-side. - Add a custom LLM tag for the offending subsystem.
- Re-run to verify the fix.
PerfGuard can launch the test scenario with -trace=default,memory,memalloc,memtag,metadata,assetmetadata,bookmark + -llm -llmcsv, parse the per-LLM-tag CSV, and emit per-tag delta vs baseline alongside CPU/GPU regressions. UE 5.6 AssetClass-level deltas surface in the same regression report — flag a StaticMesh or Texture budget regression with the same red/green PASS/FAIL UX as a CPU spike.
- Memory & VRAM Optimization — what to do once you've identified the leak.
- Loading Time Optimization — async loading patterns that affect memory.
- Gotcha #10: Garbage Collection Hitches — the GC connection.