Explaining The Heap
The aim of this pageπ is to explain the heap β what it is, how it differs from the stack, and why C programmers must manage it explicitly.
1. Two runtime memory regions
- stack and heap are both runtime regions inside a processβs virtual address space
- the distinction only exists at runtime β compile time decides strategy, runtime populates/depopulates
- virtual address space layout (simplified):
2. Thread:Stack is 1:1 β Thread:Heap is many:1
- every thread owns exactly one call stack
- all threads share one heap
- stack = private β thread-safe by default
- heap = shared β needs synchronization under concurrent access
- think of threads as equalizer bars: each bar (thread) has its own height (stack depth)
- the heap is a different dimension β outside the equalizer, persistent, reachable from any bar
https://gist.github.com/pkutaj/f038f4bfcd1a51d1cbe38fe6a39dcc05
- stack frames are temporary β exist only for the duration of a call
- heap objects are long-lived β survive across frames, reachable via pointers
3. Stack: fast, automatic, scoped
- in C, function arguments are copied onto the stack frame (pass-by-value)
- local variables also live in the frame
- once the function returns, the frame is gone β memory is reclaimed automatically
- the CPU has native instructions for stack push/pop β very fast
Example function β all data fits on the stack:
Stack frame for this call:
C type sizes (platform-dependent):
Get Pavol Z. Kutajβs stories inΒ yourΒ inbox
Join Medium for free to get updates fromΒ thisΒ writer.
https://gist.github.com/pkutaj/3028f854fbed57c804939c2a4a06c6dd
4. Heap: slow, manual, process-wide
- heap memory is not automatically freed β you must explicitly release it
- forgetting to free = memory leak β process slowly consumes all available RAM
- heap is slower: the allocator must find a free block, track metadata, handle fragmentation
The three reasons to reach for the heap:
- Unknown size β size is not known at compile time; must allocate dynamically at runtime
- Cross-scope / long-lived β data must outlive the function that created it
- Too large β stack is typically 1β8 MB; large buffers must go on the heap
Rule of thumb:
- stack when size is known ahead of time and data lives within one function
- heap when size is unknown or data must survive across function boundaries
5. malloc and free β the C heap API
malloc(size_t n)β asks the OS fornbytes on the heap; returnsvoid *- cast to your target type:
(int *) sizeof(int)is idiomatic β let the compiler determine size, don't hardcode4free(ptr)β returns memory to the OS; omitting it = leak
6. Aside: you canβt shovel the heap onto the wire
- if the call stack is a stack data structure (of frames), the heap is a graph (of pointers)
- pointers are virtual addresses β process-local, ephemeral
0xFF1234is meaningful only inside this running process- different run, different machine β that address is garbage
- heap also contains allocator metadata, padding, alignment gaps
- ASLR (Address Space Layout Randomization) randomizes base addresses on every run
- serialization = traverse the pointer graph, emit only values
- deserialization = rebuild the pointer graph on the other end
- this is why every network protocol, file format, and IPC mechanism involves serialization
Why columnar formats (e.g. ClickHouse) are fast on the wire
- columns are already close to wire-ready: contiguous values, same type
- minimal pointer indirection to resolve before sending
- contrast with row-oriented formats where each row may contain pointers to variable-length strings
References
- [1] C Programming and Memory Management β Full Course: https://gist.github.com/pkutaj/ab31afb79199729daca7ac6131e4f802
- [2] TJ DeVries β C and Memory Management: https://www.youtube.com/watch?v=rJrd2QMVbGM
- [3] K&R β The C Programming Language (Kernighan & Ritchie)
- [4] Divio Documentation System: https://docs.divio.com/documentation-system/
- [5] DDIA β Formats of Encoding: https://tinyurl.com/DDIA-formats-of-encoding
- [6] DDIA β Modes of Dataflow: https://tinyurl.com/DDIA-modes-of-dataflow






