Skip to content

Memory

What the engine is holding, and how much headroom is left. On a phone this is the difference between a slow game and a killed one — the OS doesn't slow you down when you run out, it terminates the process.

Unlike the Profiler counters, Memory works in every build, not just Development.

Memory.Used

Total bytes the engine is currently holding.

csharp
Log.Info($"using {Memory.Used / (1024 * 1024)} MB");

Memory.UsedBy(MemoryCategory category)

The same, broken down.

csharp
ulong textures = Memory.UsedBy(MemoryCategory.Textures);

MemoryCategory

Textures, Audio, Meshes, Scenes, Scripts, Shaders, UI, Other.

Textures dominate a 2D game almost every time. If a build is over budget, that's the first row to look at.

Memory.Peak

The highest Used has been this session. This is the number that matters on mobile — the OS reacts to your high-water mark, not your average.

Memory.ResetPeak()

Starts a fresh peak measurement — so you can measure one level, or one boss fight, rather than the whole session.

csharp
protected override void OnCreate()
{
    Memory.ResetPeak();
}

Memory.Available

How much headroom is left before you're in trouble.

Memory.Budget

The ceiling, where the platform reports one. 0 where it doesn't.

Memory.DriverUsed

What the graphics driver says it's using — a cross-check against the engine's own accounting, useful when the two disagree.

Memory.IsUnified

Whether RAM and video memory come from the same pool. true on phones and on Apple silicon, where a texture upload costs you main memory too.

Memory.PollPressure()

Whether the OS is currently asking for memory back.

csharp
protected override void OnUpdate(float ts)
{
    if (Memory.PollPressure())
        DropOptionalAssets();
}

The mobile hooks aren't wired yet

PollPressure() and Budget are the right shape, but the OS notifications that should drive them are not connected on Android or iOS in 0.1.0 — the platform where running out of memory is a process kill. Treat them as reliable on desktop and as best-effort on mobile, and lean on Available and your own testing there.

The engine never enforces a budget

Budget is a number your game can watch and log against. The engine will not refuse a load or evict a visible asset to stay under it — that's a deliberate boundary, not an oversight. Acting on the number is your job:

csharp
public class MemoryWatchdog : GameEntity
{
    private float m_NextCheck;

    protected override void OnUpdate(float ts)
    {
        if (Time.TimeSinceStartup < m_NextCheck)
            return;
        m_NextCheck = Time.TimeSinceStartup + 1f;

        if (Memory.Budget > 0 && Memory.Used > Memory.Budget * 0.85f)
            Log.Warn($"memory at {Memory.Used * 100 / Memory.Budget}% of budget");
    }
}

Finding a leak

Load a scene, unload it, and watch Memory.Used come back to roughly where it started. If it climbs every cycle, something isn't being released — usually an entity that never gets destroyed, or an asset still referenced by a script that outlived its scene.

csharp
private System.Collections.IEnumerator LeakCheck()
{
    ulong before = Memory.Used;
    Scenes.Load("Level1");
    yield return 2f;
    Scenes.Load("MainMenu");
    yield return 2f;
    Log.Info($"delta after one cycle: {(long)Memory.Used - (long)before} bytes");
}

See also

  • Performance — texture compression, pooling, allocation discipline
  • The Profiler — the Memory view, with the same numbers in a panel
  • Profiler — per-frame managed allocation counters
  • Scenes — unloading to free memory