C++ Stack vs Heap — Complete Guide
이 글의 핵심
C++ stack vs heap: stack overflow from deep recursion and huge locals, memory layout, performance, new/delete, smart pointer lead-in—Valgrind and ASan-friendly mental model.
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_ptr for sole ownership
- shared_ptr when 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 -s to 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_ptr only 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
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- [C++ Memory Leaks](/en/blog/cpp-series-06-2-memory-leak/
- [Rust Memory Safety: Ownership, Borrowing, Lifetimes, unsafe](/en/blog/cpp-series-47-3-rust-memory-safety/
- [Rust Ownership | Ownership, Borrowing, and Lifetimes](/en/blog/rust-series-02-ownership/
- [Python Data Types | Lists· Dictionaries](/en/blog/python-series-03-data-types/
- [C++ Memory Management: new/delete, Stack vs Heap, and RAII](/en/blog/cpp-memory-management-deep/
이 글에서 다루는 키워드 (관련 검색어)
C++, Memory Management, Stack, Heap, Pointer, Memory Layout, Valgrind 등으로 검색하시면 이 글이 도움이 됩니다.