Help home · Guides

Compare memory between level visits

The debugger's Memory view helps you check what remains after leaving a level. Reports describe allocations, references and reusable capacity. Growth alone does not establish a leak.

Take a baseline

  1. Start a debug run and pause at your game's menu.
  2. Open Memory and choose Take Snapshot. Your first report becomes the baseline automatically.
  3. Resume, play and leave a level, then pause and capture again.
  4. Choose Compare. Inspect positive byte and count changes, then expand the relevant Type or category.
  5. Rename reports to describe the game state. Select a retained report and choose Set Baseline to compare from that point.
  6. Choose Export to save the selected report, baseline and calculated changes as UTF-8 JSON. Desktop uses Save; web downloads a file. Export never recaptures.

You must pause before debugger capture. Failed captures leave the last successful report and baseline intact. The view retains up to eight reports, keeping your baseline while evicting the oldest other report. Captures survive the end of a run, but history clears when a new run starts. An abrupt crash cannot guarantee a final capture.

Read the figures

Type bytes are shallow pool storage. Referenced strings, collections and other Types remain in their own categories. Per-Type rows break down the Types category rather than adding another allocation. Types with no visible variable still appear if they remain in their implicit Type list. Imported and private Types use their defining module's qualified name; older native modules can show an unavailable-name label and a stable run-local identity.

Coverage and timing

The main report covers the calling runtime context, not every worker. Worker queries describe only that worker. Supplemental renderer, loading, jobs and physics figures carry their own scope, accounting basis, availability and sample time. Do not add them to the runtime total or each other. Audio and unmeasured native allocations are explicitly unavailable.

Renderer figures describe the published sample, without waiting for GPU completion. DX12 includes shadow allocations with textures; Metal groups them with render targets. WebGPU tracks resource sizes rather than driver residency. Linux native Dawn/Vulkan is identified separately from browser WebGPU. Console-only and software-2D runtimes leave unsupported 3D metrics unavailable. Revisit a comparison after asynchronous work settles naturally; capture itself does not finish jobs, flush caches or force collection.

Capture from your program

MemorySnapshot$() works without graphics or a debugger, including mobile programs. Its returned String is charged after the captured scalars are copied. Keeping that String affects the next report, and even releasing it immediately can raise the lifetime peak. A small helper keeps temporary values out of the next measurement:

Function ExportMemory(path$)
    Local report$=MemorySnapshot$()
    Local file=WriteFile(path)
    If file=0 Then RuntimeError "Cannot open memory report"
    WriteLine file,report
    CloseFile file
End Function

Call the helper only for a file you intend to create or replace. It returns before the next capture, releasing its report String. If you parse reports with ParseJson, release every owned JsonObjectGet or JsonArrayGet result and the root with FreeJson too.

Try the complete Memory Reporting sample. It captures a baseline, deliberately retains Types, a List and a Bank, shows deleted aliases, cleans up, and repeats the cycle to demonstrate stable reuse. The debugger can perform the same comparisons without adding queries to your game.

Export and compatibility

The versioned JSON uses decimal strings for counts and bytes, including values above 2^53; differences are signed decimal strings. Keep those strings lossless in JavaScript tools. Reports include run/context identities, capture sequence, timestamp, coverage revisions and explicit unavailable or incomplete detail. Compare only matching run/context, schema and metric coverage. An omitted Type is unknown, not zero. In-run comparison is supported; cross-run import is outside this release.

Reports are limited to 1 MiB, with bounded names and per-Type details. Category totals stay intact if detail rows are omitted. The runtime retains no report handles or baselines and copies no live object references into a report.