Memory Management
Lesson outline
Memory Management Overview
Memory management in C++ refers to how programs request, use, and release memory during execution. Unlike garbage-collected languages, C++ gives developers explicit control over allocation and deallocation.
Core concepts include:
- Stack vs Heap: Different storage regions with distinct lifetimes
- Manual Allocation: Using
new/delete(andnew[]/delete[]) for dynamic memory - RAII (Resource Acquisition Is Initialization): Binding resources to object lifetimes
- Smart Pointers: Modern tools for safer memory management
- Common Errors: Memory leaks, dangling pointers, buffer overruns, double delete
Memory Segments in C++
| Memory Segment | Description | Characteristics |
|---|---|---|
| Stack | Automatic storage for local variables | Very fast allocation/deallocation; limited size; automatically released when scope ends |
| Heap | Dynamic storage managed by the runtime allocator | Manually managed (or via smart pointers/containers); allocation/deallocation typically slower than stack; access speed depends on locality/caching, not on 'being heap' |
| Global/Static | Holds objects with static storage duration (globals, static variables) | Allocated once and persists for the program lifetime |
| Code (Text) | Executable program instructions | Generally read-only/executable; laid out by the toolchain and loaded by the OS |
| Memory-mapped | OS-provided mappings (e.g., files/devices) exposed as memory | Platform-dependent; useful for I/O and IPC |
Stack vs Heap Memory
Stack objects are reclaimed automatically when they go out of scope. Heap allocations provide flexibility but require correct and matching deallocation.
RAII and Smart Pointers (Modern C++)
RAII ties resource lifetime to object lifetime, ensuring release in destructors - even on exceptions. Prefer smart pointers over owning raw pointers:
std::unique_ptr: sole ownership, no copy, cheap movestd::shared_ptr: shared ownership via reference countingstd::weak_ptr: non-owning observer to break cycles and check liveness
Prefer Standard Containers
Instead of manual new[] and raw arrays, use containers that manage memory automatically:
std::vector,std::string,std::array,std::map, etc.
These provide bounds-aware operations, exception safety, and fewer lifetime bugs.
Safe Allocation/Deallocation Rules
- Match
newwithdeleteandnew[]withdelete[]. - Never free memory with a different mechanism than it was allocated with.
delete nullptr;is safe and has no effect.- After manual
delete, setting the pointer tonullptrcan help avoid accidental reuse (not needed with smart pointers). - Be careful with ownership transfer; document who owns and frees a resource.
Common Memory Issues
- Memory Leak: Allocated memory never released
- Dangling Pointer/Reference: Refers to freed or out-of-scope object
- Double Delete: Releasing the same allocation twice
- Buffer Overflow/Underflow: Writing outside allocated bounds
- Fragmentation: Many differently sized allocations causing gaps
- Shared Ownership Cycles:
shared_ptrcycles that prevent reclamation (useweak_ptr)
Debugging & Tools
Use tooling to detect bugs early:
- AddressSanitizer (ASan), UndefinedBehaviorSanitizer (UBSan)
- LeakSanitizer (LSan), ThreadSanitizer (TSan)
- Valgrind or platform-specific heap checkers
Enable runtime checks and compile with warnings elevated where possible.