"Stack overflow" and "the heap is fragmented" are phrases every programmer eventually hears — this lesson is what they actually refer to: two very differently-managed regions inside every running program's own memory.
3 min read
When a process starts, the operating system gives it a private virtual address space (lesson 6 covers why it's virtual). That space isn't one undifferentiated blob — it's divided into distinct regions, each with a different purpose and a different management strategy:
Every function call pushes a new stack frame — space for that function's local variables, its arguments, and the address to return to once it finishes. When the function returns, its frame is popped off and that memory is immediately reclaimed, automatically, with no explicit cleanup needed. This automatic, predictable lifetime is what makes stack allocation extremely fast — it's just moving a pointer up or down — but it also means stack memory only exists for as long as the function call that owns it is still running.
A stack overflow happens when this region runs out of space — most often from runaway recursion (a function that keeps calling itself without a base case that's ever actually reached), where each recursive call pushes another frame until the stack's fixed size is exhausted.
The heap is for data whose lifetime doesn't match any single function
call's — an object that needs to outlive the function that created it, or
whose size isn't known until the program is actually running. Heap memory
has to be explicitly requested (malloc in C, new in many
languages) and, in languages without a garbage collector, explicitly
released — forgetting to do so is a memory leak, and releasing it twice
or using it after release is a serious class of bug in those languages.
Languages with a garbage collector (Python, JavaScript, Java, Go) automate the "release" half of this — the collector periodically finds heap objects nothing references anymore and frees them — trading some runtime overhead and less precise timing for eliminating an entire category of manual-memory bugs.
Stack allocation is just adjusting one pointer — no search, no bookkeeping. Heap allocation has to find a suitably-sized free block among memory that's been allocated and freed in an arbitrary order over the program's lifetime (this is where heap fragmentation comes from), which is inherently more work. This is a large part of why performance-sensitive code favors stack-allocated, fixed-size data wherever the data's lifetime genuinely matches a function call.
Lesson 2 mentioned that each thread gets its own stack while all threads in a process share one heap. This is exactly why: a stack's contents are tightly scoped to one specific sequence of function calls, so giving each thread its own makes sense. The heap holds data meant to be shared or to outlive any single call, so one heap per process is the natural design.
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. Why is stack allocation faster than heap allocation?
2. What most commonly causes a stack overflow?
3. Why does each thread get its own stack while all threads in a process share one heap?
Operating Systems Fundamentals