Skip to content
ByteStepStart with recursion

The call stack, and what "stack overflow" means

Free, no account

Every call needs somewhere to keep its own work: which number it was given, how far through the function it had got, and where to go back to when it finishes. In the last lesson that place had a name. It is a stack frame, and the calls waiting on each other were a column of them.

What that lesson left out is that the column has a floor. The space those frames come from was set aside before your program started running, it does not grow, and a program that keeps calling without ever coming back will use all of it. When that happens the program does not slow down or return a wrong answer. It stops.

Below is the same stack you already know, drawn as the memory it actually is: real addresses, a fixed number of bytes per frame, and an end. Run sum first and watch the region fill and empty. Then switch to runaway, which forgot its base case, and watch it hit the bottom.

1function sum(n) {
2 if (n <= 1) return 1
3 const rest = sum(n - 1)
4 return n + rest
5}

The stack, in memory

one frame per call, and the room that is left

Stack · 640 Bhigh address
0x7FFBFD80 · limit0/10 frames · 0 B

An empty stack, with room for 10 frames and not one more. Every call about to happen has to fit in here.

1/12
Detail
12 steps

Why the stack has an end, what fills it, and why a loop does not.

The stack is a place, not a list

A list grows as long as you need. The stack does not. It is a region of memory with a first address and a last one, handed to your program when it starts, and every frame is carved out of that fixed space. This is why the animation draws the empty rows: the room that is left is as much a part of the picture as the frames that are using it.

Notice the direction. The first frame sits at the highest address and each new one is placed below it. That is not a drawing choice. On x86-64, Arm and every other mainstream architecture, the stack grows downwards from a high address towards lower ones, which is why the limit in the animation is at the bottom rather than the top.

Where the bytes go

Each frame in this lesson takes 64 bytes, which is a realistic figure for a function this small: room for the address to return to, the caller's frame pointer, a local or two, and the padding the machine insists on for alignment. Change n and watch the usage figure underneath. It is always the number of frames multiplied by the size of one, because nothing else is in there.

That is the cost recursion has and a loop does not. Depth is memory. Ten calls deep is ten frames alive at once, and all ten are still holding their values, because not one of them has finished.

Running out

runaway is sum with the stopping condition deleted. It is not an exotic mistake. It is the single most common way a recursive function goes wrong, and it comes in two flavours: forgetting the base case, and writing one that the input never reaches.

Watch what happens at the bottom. The call asks for a frame, there is nowhere to put it, and the program stops there. It does not overwrite something else and carry on. It does not free an old frame to make room, because every one of those frames is still waiting for an answer. Nothing can be thrown away, and nothing more can be added, so there is nothing left to do.

That is a stack overflow. The name is literal: the thing that overflowed is the stack, and it overflowed because it was a container all along.

The fix is usually a loop

Switch to loop and set n as high as it will go. One frame. The same frame, reused, for every value from n down to one. Iteration keeps its working values in the frame it already has, so its memory cost does not change with the size of the problem.

That is the trade, stated plainly: recursion buys code that matches the shape of the problem, and pays for it in frames. When the depth is small, or bounded by the structure you are walking, the price is nothing. When the depth grows with the input, the price is the whole stack.

Know someone stuck on this? Send it to them.

A classmate, a study group, someone learning this on their own at midnight. The link opens the lesson set up exactly as you have it, the same function and the same number, and runs from the first step so they watch the whole thing build rather than landing in the middle of it.

Before this one

Recursion: how a function calls itself

Where the frames in this lesson come from, and why each one keeps its own copy of the value it was given.

Start there →