C++ Stack vs Heap | Why Recursion Crashes and Real Stack Overflow Cases
이 글의 핵심
Stack vs heap in C++: recursion crashes, stack overflow, size limits, when to use vector on the heap, and how stack frames work—foundation for smart pointers and RAII.
Introduction: Crashed by stack overflow
Why the process died — recursion trap
You implemented Fibonacci recursively. n = 10 worked; n = 100000 killed the process with no helpful message. The stack is a small, fast region—like a narrow workbench: deep recursion stacks many frames, each holding locals, until the bench overflows.
The demo below stacks ~4KB per call (int cache[1000]) and explores two branches—stack usage explodes. fibonacci(100000) exceeds the process’s stack limit → stack overflow. (The cache array is unused in logic—it illustrates per-frame stack cost.)
// g++ -std=c++17 -o fib fib.cpp && ./fib
#include <iostream>
int fibonacci(int n) {
int cache[1000]; // ~4KB per frame
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
int main() {
std::cout << fibonacci(100000); // crashes — stack overflow
return 0;
}
Debugging path:
- Logic bug? → not here
- Leak? → Valgrind says no
- Stack overflow — stack limit exceeded
Takeaway: know stack vs heap; huge locals and deep recursion are dangerous on the default stack.
After reading:
- How stack and heap behave
- How to avoid stack overflow
- When to use stack vs heap
- How layout fits later smart pointers and RAII
Previous: Compilation process
Table of contents
- Process memory layout
- Stack memory
- Heap memory
- Stack vs heap performance
- Selection guide
- Complete examples
- Common memory errors
- Debugging tips
- Production patterns
1. C++ process memory (simplified)
The OS maps text (code), data/BSS (globals), heap (grows up), and stack (grows down). If stack and heap meet, you’re in trouble.
flowchart TB
subgraph addr["Address direction (low → high)"]
direction TB
T[Text code]
D[Global/static Data, BSS]
H[Heap ↑]
free[Free space]
S[Stack ↓]
end
T --> D --> H --> free --> S
style H fill:#e1f5fe
style S fill:#fff3e0
| Region | Role | Lifetime |
|---|---|---|
| Stack | Locals, args, return addresses | Until scope returns |
| Heap | new / malloc | Until freed or process exit |
Why stacks are small: one stack per thread; deep recursion and large frames consume it quickly—typically ~1–8MB per platform default.
2. Stack memory
Fast, automatic, limited. Each function call pushes a stack frame (locals, saved state).
Advantages:
- Fast—just move the stack pointer
- Automatic—destroyed on scope exit
- Cache-friendly—contiguous
Disadvantages:
- Small—don’t put megabytes as
int huge[1000000]local - Lifetime tied to scope—returning address of a local → dangling pointer
Stack overflow examples
Huge local array → use std::vector on the heap.
Deep recursion with big locals → reduce depth, move arrays to heap, or iterate.
Mitigation (last resort):
ulimit -s 16384 # Linux: 16MB (example)
Root fix: don’t rely on giant stacks—heap or iteration.
3. Heap memory
Flexible size and lifetime; you (or smart pointers) must free it.
Pros: large allocations, outliving scope, polymorphic arrays
Cons: slower, fragmentation risk, manual correctness without RAII
4. Stack vs heap performance
Microbenchmarks often show stack allocation ~orders of magnitude faster than new/delete in tight loops—don’t micro-optimize hot loops with per-iteration heap allocs.
5. Selection guide
- Small, local, short-lived → stack
- Large, shared, runtime-sized, polymorphic → heap +
vector/unique_ptr
6. Patterns
unique_ptrfor sole ownershipshared_ptrwhen shared (watch cycles →weak_ptr)- RAII wrappers for buffers and files
7. Common errors
- Stack overflow — huge locals / deep recursion
- Dangling pointers — address of stack local returned
deleteon stack memory — undefined- Double free / use-after-free
- Leak —
newwithoutdeleteon all paths
8. Debugging tips
- Valgrind / ASan (
-fsanitize=address) for heap corruption and leaks - GDB + core for post-mortem stack traces
ulimit -sto inspect stack limit
9. Production patterns
- Object pools to cut repeated
new/delete - Stack allocators / arenas for frame-scoped bump allocation
- Default to
unique_ptr,shared_ptronly when needed
FAQ
Biggest difference stack vs heap?
A. Stack auto-managed, tiny, fast; heap flexible and large but manual (or smart pointers).
How to prevent stack overflow?
A. Avoid huge stack arrays; limit recursion depth; use heap containers; iterate.
Stack vs heap speed?
A. Microbenchmarks often show 50–100× gap for raw alloc vs stack pointer bump—measure your workload.
Why not return address of stack variable?
A. After return the frame is gone—dangling pointer → UB.
Related posts
- Memory leaks
- Smart pointers
- RAII
Keywords
C++ stack vs heap, stack overflow, memory layout, dangling pointer, heap allocation, recursion
Summary
- Stack: fast, automatic, limited
- Heap: flexible, must manage (prefer smart pointers)
- Default: small locals on stack; large data on heap
- Watch recursion and large arrays on the stack
Next: Memory leaks #6-2
References
Practical tips
Debugging
- Enable warnings; reproduce minimally
Performance
- Profile before optimizing
Related posts
- Stack vs heap (alternate slug)
- Valgrind