The stack and heap are two fundamental regions of memory used during program execution, each serving different purposes and with distinct management strategies.

The Stack

The stack is a contiguous block of memory allocated per thread to manage function calls, local variables, and return addresses. It operates like a real stack data structure (LIFO) with explicit push and pop operations.

The compiler is responsible for generating assembly instructions to handle stack operations:

  • Function calls push arguments, local variables, and the return address onto the stack.
  • Function returns pop these values, restoring the previous state.

The operating system allocates the stack:

  • For the main thread, the stack is allocated at program startup.
  • For additional threads, the stack is allocated at thread creation, with default sizes (e.g., 1 MB on Linux) that can be adjusted using APIs like pthread_attr_setstacksize.

While the stack resides in user space, the kernel ensures protections, such as detecting stack overflows and enforcing non-executable stack policies.

The Heap

The heap is a large, flexible region of memory used for dynamic allocations. Unlike the stack, it does not follow a LIFO structure and allows memory to be allocated and freed in arbitrary order. The heap is an abstraction built on low-level system calls and the C memory allocators take care of managing problems such fragmentation.

Why Is the Stack a Real Stack but the Heap Is Not a Real Heap?

The stack operates exactly like a stack data structure, with well-defined push and pop semantics for function calls and control flow. In contrast, the heap does not resemble a heap data structure (used for priority queues) but is instead a large, flexible pool of memory blocks. The name “heap” in memory likely comes from the idea of a “pile” or “heap” of memory resources available for arbitrary use.