[2026] C++ Stack vs Heap | Why Recursion Crashes and Real Stack Overflow Cases

[2026] C++ Stack vs Heap | Why Recursion Crashes and Real Stack Overflow Cases

이 글의 핵심

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 limitstack overflow. (The cache array is unused in logic—it illustrates per-frame stack cost.) 다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 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:

  1. Logic bug? → not here
  2. Leak? → Valgrind says no
  3. Stack overflow — stack limit exceeded Takeaway: know stack vs heap; huge locals and deep recursion are dangerous on the default stack. After reading:

Table of contents

  1. Process memory layout
  2. Stack memory
  3. Heap memory
  4. Stack vs heap performance
  5. Selection guide
  6. Complete examples
  7. Common memory errors
  8. Debugging tips
  9. 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. 아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 실행 예제
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
RegionRoleLifetime
StackLocals, args, return addressesUntil scope returns
Heapnew / mallocUntil 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:

  1. Fast—just move the stack pointer
  2. Automatic—destroyed on scope exit
  3. Cache-friendly—contiguous Disadvantages:
  4. Small—don’t put megabytes as int huge[1000000] local
  5. 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

  1. Stack overflow — huge locals / deep recursion
  2. Dangling pointers — address of stack local returned
  3. delete on stack memory — undefined
  4. Double free / use-after-free
  5. Leaknew without delete on 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 pointerUB.

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

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3