Stack vs heap
“Where do local variables live and where do objects live? Why does the split exist, and what does each choice cost?”
What this tests
- Stack as per-thread, LIFO, lifetime tied to the frame
- Heap as process-wide, arbitrary lifetime, managed by an allocator
- Why the split exists: known vs unknown lifetime
- Costs: allocation speed, fragmentation, overflow, RSS behaviour after free
Answers by level
Read the beginner answer first and notice what is missing.
The stack is a per-thread, contiguous region of the address space that grows and shrinks with function calls. A call pushes a frame — return address, saved registers, locals; a return pops it. Allocation is "move the stack pointer", freeing is implicit, and a local cannot outlive its frame: its lifetime is exactly the call. The size is fixed at thread creation — 8 MB of virtual space for the main thread on Linux by default (ulimit -s), 1 MB on Windows, whatever pthread_attr_setstacksize says for other threads — with a guard page beneath so that running past the end faults instead of corrupting memory (Stack Frames, Stack Overflow).
The heap is the process-wide pool for data whose lifetime is not tied to any call: it is created in one function and used long after that function returned. An allocator (malloc/free, new/delete, or a garbage collector in managed languages) carves it out of large regions obtained from the kernel with brk/sbrk and mmap. Because objects are freed in arbitrary order, the allocator must manage free lists, size classes and fragmentation, and a lookup is tens of nanoseconds rather than one instruction (What Happens When I Allocate Memory?).
So the split exists because of lifetime knowledge: when the compiler knows an object dies with the call, the stack is free; when it does not, something has to track it. In C++ you choose per object; in JavaScript and Python every object lives on the heap and locals are references to them, though JITs (V8, PyPy) use escape analysis to keep short-lived objects out of the heap. Recursion has a limit because every frame consumes stack, and stack size is fixed.
To the kernel there is no "stack" or "heap" — they are mappings in the address space (The Process Memory Layout). Which is why the failure modes differ: a stack overflow is a SIGSEGV at the guard page (or RangeError/RecursionError in runtimes that count); a heap problem is a leak, a use-after-free, or an RSS that never shrinks because free gave memory back to the allocator, not to the OS.
Green flags · Red flags
- Explains lifetime as the reason for the split
- Describes the stack as per-thread with a fixed size and a guard page
- Knows the heap is managed by an allocator with fragmentation and free lists
- Says the kernel only sees mappings
- Mentions that free does not necessarily shrink RSS
- "Stack is faster" with no reason
- Believes the heap is a fixed region set by the OS
- Thinks stack overflow corrupts the heap