โ† the Lab

A frame with zero allocations

exploring arena allocators ยท started 10 June 2026

The problem

A game running at 60fps has 16.6 milliseconds to produce each frame. Miss that budget and the frame is late โ€” the player sees a hitch. The sneakiest way to blow it is a heap allocation inside the game loop. Most of the time it's cheap, which is exactly what makes it dangerous: it hides. Then on one frame in a thousand it isn't cheap, because the allocator hit a slow path, the free list had fragmented, or the operating system had to hand back a fresh page of memory.

That's the trap with frame pacing: it's a worst-case problem, not an average one. You can allocate ten thousand times with a lovely average and still ship a visible stutter, because the player feels the one frame that ran long, not the mean. General-purpose allocators are tuned to make the average good and to be safe across every possible usage pattern โ€” which is the right goal for most software and the wrong guarantee for a real-time loop, where predictability matters more than raw speed.

How I'm approaching it

The move is to stop asking the general-purpose heap for per-frame memory at all. Almost everything a frame allocates is transient โ€” this frame's particle list, the popup queue, scratch space for pathfinding โ€” and all of it can die at the end of the frame. So I hand that work to an arena: a single block of memory reserved once, up front.

Allocating from an arena is trivial: you keep a marker for how far you've filled it, and each request just hands back the next slice and advances the marker. There's no bookkeeping, no search for a free block, no chance of fragmentation. And freeing is the good part โ€” you don't free objects one by one. At the top of the next frame you reset the marker back to the start, and the entire frame's worth of allocations is gone in a single operation. Releasing ten thousand objects costs exactly the same as releasing one.

Long-lived things โ€” textures, audio, the world itself โ€” still live on the normal heap. The arena only owns the churn: the memory whose timing you can't afford to gamble on. That split is the whole trick.

The bottlenecks I'm watching

The open question

The honest hard part is that sizing number. Rather than pick it by guess, my plan is to instrument peak per-frame arena usage while the game runs through its heaviest moments, and set the reservation from the measured p99 โ€” big enough to swallow the worst real frame, not so big that a WASM build pays for headroom it never touches. Measure first, then commit the number.

What I expect to see

Success here doesn't look like a higher average frame rate โ€” it looks like a flatter one. The metric I'm after is the frame-time graph: the general-heap version should show occasional tall spikes where an allocation hit a slow path, and the arena version should erase them, leaving a much tighter band. If the p99 and p99.9 frame times collapse toward the median while the average barely moves, that's the win โ€” the stutter is gone even though the typical frame was never the problem. If the spikes were coming from somewhere else entirely, I'd rather find that out than assume.

What I'm looking into next

Done this before? If you've fought frame-time spikes in a real engine and have a sharper way to size or structure this โ€” or a reason an arena bites back โ€” I'd love to hear it. Drop me your suggestions โ†’
โ† back to the Lab