Ch. 21 · Operating Systems

Operating Systems: Memory Allocation

Compare stack and heap allocation, how the allocator manages the heap, and the fragmentation and lifetime bugs that follow.

~2 min readintermediateupdated Oct 5, 2026

Programs use two main kinds of memory: the stack for call frames and local variables, and the heap for dynamically allocated data whose lifetime is not tied to a call. The stack is fast and reclaimed automatically; the heap is flexible and requires an allocator and explicit or garbage-collected release.

Before you start

You should understand processes and virtual memory at a high level. This article covers allocation strategy and its failure modes.

Step-by-step walkthrough

Step 1: Know which region you are using

Stack allocation happens as functions are called and returns automatically when they return, in LIFO order. Heap allocation is requested from an allocator and freed when the program decides, so it can outlive the call. Choosing the stack for short-lived locals and the heap for shared or long-lived data is the first decision.

Step 2: Understand what the allocator does

The allocator requests pages from the OS and hands out smaller blocks, tracking free space. Repeatedly allocating and freeing different sizes leaves gaps, so fragmentation can prevent a large allocation even when total free memory is enough. Allocators use size classes and arenas to limit this.

Step 3: Manage lifetime correctly

Heap memory is released manually in languages like C and automatically by a collector in languages like Java and Go. Manual release risks leaks (never freed) and use-after-free (freed then used), while collection trades throughput for safety. Know which model your language uses.

Worked scenario

The heap block outlives nothing but must be freed explicitly.

int *values = malloc(10 * sizeof(int));
if (values == NULL) { /* allocation failed */ }
values[0] = 1;
free(values);
/* values now dangles; using it is a use-after-free */
c

Walk through the example

malloc returns a heap block whose size is known to the allocator, so free needs only the pointer. Failing to check for NULL risks a dereference of nothing; failing to call free leaks; using values after free is undefined behavior. The allocator cannot detect a dangling pointer, which is why these bugs are dangerous.

Common mistake

Leaking heap memory in a long-running loop until the process is killed, or using memory after freeing it, which corrupts unrelated data. Another is assuming malloc returns zeroed memory; it does not.

Verify the behavior

Run a leak detector or heap profiler and confirm allocations are balanced with frees. Request a large block after many small frees and observe whether fragmentation prevents it. Access a freed pointer under a sanitizer and confirm it is reported.

Interview exercise

Why can a program run out of memory even with free memory available?

Answer and reasoning

Because fragmentation can split free memory into gaps too small for the requested block. Even if the total free bytes exceed the request, no single contiguous region may be large enough, so the allocation fails. Allocators mitigate this with size classes and arenas, and compaction helps where the language allows it.

Continue learning

Compare memory topics in Stack and heap and Virtual memory. Read the Linux malloc documentation and try the Operating systems interview questions.

More in Operating Systems

read ✓Operating Systems · hard

Copy-on-Write Memory and fork

How copy-on-write lets fork share pages until a write, why RSS can be misleading, and the implications for memory and latency.

~2 min readread →
read ✓Operating Systems · mid

Operating Systems: Swap and Thrashing

How swapping extends memory, when it becomes thrashing, and how overcommit and the OOM killer respond to exhaustion.

~2 min readread →
read ✓Operating Systems · hard

Operating Systems: CPU Cache Locality

Improve performance with spatial and temporal locality, avoid pointer chasing, and understand false sharing between threads.

~2 min readread →
esc