Stack, Heap, mmap

Every running Linux process has its own virtual memory layout.

Inside that layout are several important regions. Three of the most important are:

A process does not simply have “memory.” It has a structured virtual address space, divided into regions with different purposes.

High-Level Memory Layout

A simplified Linux process layout looks something like this:

High Memory ──────────────────────────────── Stack ↓ grows downward Memory mappings shared libraries files mapped with mmap() anonymous mmap regions Heap ↑ grows upward Program data global variables static variables Program text machine code ──────────────────────────────── Low Memory

The exact layout depends on architecture, kernel settings, address-space randomization, executable type, shared libraries, and runtime behavior.

The diagram is conceptual. Linux may place regions differently, but the core idea remains: a process has separate regions for code, data, stack, heap, and mappings.

The Stack

The stack is used for function calls and short-lived automatic storage.

When a function is called, Linux and the CPU cooperate with the program’s calling convention to build a stack frame.

Stack Usually Contains

Simple Stack Example

#include <stdio.h> void greet() { int number = 42; printf("Number: %d\n", number); } int main() { greet(); return 0; }

The variable number is an automatic local variable. It normally lives in the stack frame for greet().

Stack Growth

On many common systems, the stack grows downward, from higher virtual addresses toward lower virtual addresses.

If a program uses too much stack memory, it can hit the stack limit and crash with a stack overflow.

The Heap

The heap is used for memory that is requested while the program is running.

In C, this commonly happens through malloc(), calloc(), realloc(), and free().

Simple Heap Example

#include <stdio.h> #include <stdlib.h> int main() { int *numbers = malloc(10 * sizeof(int)); if (numbers == NULL) { return 1; } numbers[0] = 42; printf("%d\n", numbers[0]); free(numbers); return 0; }

The pointer variable numbers may live on the stack, but the memory it points to lives in dynamically allocated memory.

Stack memory is automatically managed by function calls. Heap memory is explicitly requested and released by the program.

Heap Growth

Traditionally, the heap grows upward, toward higher virtual addresses.

Modern allocators may use both the traditional heap and mmap() internally, depending on allocation size and strategy.

mmap

mmap() creates a mapping in a process’s virtual address space.

A mapping can connect part of a process’s address space to:

File Mapping Example

int fd = open("data.bin", O_RDONLY); void *addr = mmap( NULL, length, PROT_READ, MAP_PRIVATE, fd, 0 );

After this call, the process can access the file through memory addresses instead of repeatedly calling read().

Anonymous Mapping

Anonymous mappings are memory regions not directly backed by a named file. Programs and memory allocators often use anonymous mappings for large memory areas.

void *addr = mmap( NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 );

How These Regions Relate

Process Virtual Address Space +------------------------------+ | Stack | | function calls, local vars | +------------------------------+ | mmap regions | | libraries, files, anon maps | +------------------------------+ | Heap | | malloc/free dynamic memory | +------------------------------+ | Data | | globals, statics | +------------------------------+ | Text | | program machine code | +------------------------------+

These are all virtual memory regions. They appear to the process as memory addresses, but the kernel and CPU translate those virtual addresses into physical memory when needed.

Connection to Page Faults

Stack, heap, and mmap regions do not always correspond to physical RAM immediately.

A process may have a valid virtual memory region, but the physical page may not be present yet.

When a program touches a valid virtual address whose physical page is not currently ready, the CPU triggers a page fault and the kernel responds.

That is why Page Faults naturally come next.

Common Commands to Observe Memory

View a Process Memory Map

cat /proc/<PID>/maps

Example

cat /proc/$$/maps

The $$ variable expands to the current shell’s process ID.

Use pmap

pmap <PID>

Memory Summary

cat /proc/<PID>/status

Quick Comparison

Region Main Purpose Managed By ──────── ────────────────────────────────── ───────────────── Stack function calls, local variables compiler/runtime/CPU Heap dynamic allocation malloc/free allocator mmap mapped files, libraries, anon maps kernel + program request

Conceptual Summary

The stack, heap, and mmap regions are major parts of a process’s virtual memory layout.

The stack handles function-call memory. The heap handles dynamic allocation. mmap creates flexible mapped regions for files, libraries, shared memory, and large anonymous allocations.

Visual Model

See the complete Stack, Heap, MMap path as a step-by-step diagram.