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.
Log.Info($"using {Memory.Used / (1024 * 1024)} MB");Memory.UsedBy(MemoryCategory category)
The same, broken down.
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.
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.
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:
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.
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