Dynamic Memory Management
The heap is where long-lived, variable-sized data lives. Let’s master it.Understanding malloc Overhead
The Hidden Costs
Before usingmalloc, understand its costs:
The hidden work malloc does:
- Find free block: Search free list (O(n) in worst case)
- Split block: If block is larger than requested
- Update metadata: Track allocation size, free list pointers
- Alignment: Ensure proper alignment (adds padding)
- Thread safety: Lock/unlock mutex (multi-threaded programs)
- Time: ~100-500ns per allocation (200-1000 CPU cycles)
- Space: 8-16 bytes of metadata per allocation
- Fragmentation: Can waste 10-30% of heap over time
- Game engines (allocate every frame, 60 FPS = 16ms budget)
- Network servers (allocate per request, thousands/second)
- Real-time systems (unpredictable latency)
- High-frequency trading (microseconds matter)
The malloc Family
Basic Usage
realloc Gotchas
aligned_alloc (C11)
Memory Safety Patterns
Defensive Allocation
Ownership and RAII Patterns
Defer Pattern (Manual)
Custom Allocators
Why Custom Allocators?
Each allocator solves a specific problem that malloc handles poorly: Arena Allocator - Use when:- Problem: Many small allocations with same lifetime
- malloc issue: Overhead of tracking each allocation individually
- Solution: Allocate from bump pointer, free all at once
- Example: Per-request allocations in web server, temporary parsing data, compiler AST nodes
- Speedup: 10-100x faster than malloc
- Tradeoff: Can’t free individual allocations
- Problem: Many same-sized objects allocated/freed frequently
- malloc issue: Fragmentation from mixed-size allocations, search overhead
- Solution: Pre-allocate array of fixed-size blocks
- Example: Game entities, network packets, database records, object pools
- Speedup: 5-50x faster, zero fragmentation
- Tradeoff: Wasted space if pool size is wrong
- Problem: Kernel needs many instances of same struct type
- malloc issue: Initialization overhead, poor cache locality
- Solution: Caches of pre-initialized objects
- Example: Linux kernel (task_struct, inode, dentry), high-performance servers
- Benefit: Reduces initialization overhead, better cache locality
- Tradeoff: More complex implementation
Arena Allocator
Pool Allocator
Slab Allocator
Memory-Mapped I/O
Anonymous Memory Mapping
Debugging Memory Issues
Custom Debug Allocator
Exercises
1
Safe String Library
Implement
char *safe_strcat(const char *s1, const char *s2) that allocates a new string with the concatenation.2
Growing Array
Implement a dynamic array that doubles capacity when full, with
push, pop, get, and set operations.3
Arena with Chunks
Extend the arena allocator to allocate new chunks when current one is full, instead of failing.
4
Memory Tracker
Build a memory tracker that records all allocations and can print a summary of leaks at program end.
Next Up
Preprocessor Mastery
Master macros, conditional compilation, and code generation