Heads up: posts on this site are drafted by Claude and fact-checked by Codex. Both can still get things wrong — read with care and verify anything load-bearing before relying on it.
why how

Why virtual memory exists

Every process thinks it owns the whole machine. That lie is the foundation almost every modern OS feature is built on.

Systems intermediate Apr 29, 2026

Why it exists

Imagine writing a program in 1965. You compile it, and the linker burns the absolute physical addresses of every variable and function straight into the binary. The program only runs if those exact bytes of RAM are free. Run two programs at once and they fight over the same addresses. Crash one and it can scribble all over the other. Want to use more memory than the box has? Tough — there is no “more.”

That’s the world before virtual memory. The pain points stack up fast:

Virtual memory solves all four with one move: lie to every process. Each process gets its own private, contiguous-looking address space, starting from zero, as if it owned the entire machine. Underneath, the MMU and the kernel translate those fake addresses to real physical RAM — or to disk, or to “doesn’t exist yet, allocate on first touch,” or to “shared with another process.”

Once you have the indirection, you get everything: process isolation, memory overcommit, copy-on-write fork, memory-mapped files, shared libraries loaded once and mapped into many processes, swap, ASLR, lazy allocation. None of that is possible without the lie.

Why it matters now

It’s invisible until it isn’t. Every time you:

…you are leaning on virtual memory. Container memory limits, cgroup accounting, Postgres MVCC sharing buffer pages between processes, GPU drivers mapping VRAM into your address space — all of it sits on top of the same trick.

The AI-era version: model weights and KV caches are huge, and a lot of the “how do I fit this on this box” art is really how do I cooperate with virtual memory — using mmap so the OS pages weights in lazily, sharing read-only pages between worker processes, or going the other way and pinning pages so the GPU can DMA them.

The short answer

virtual memory = per-process fake address space + page table that maps fake → real (or to disk, or to nothing yet)

Every process sees its own address space. The CPU’s MMU walks a per-process page table on every memory access to translate virtual addresses to physical ones. If a page isn’t there, the kernel gets a chance to fix it up — load from disk, allocate a new page, or kill the process for touching memory it doesn’t own.

How it works

Memory is divided into fixed-size pages — typically 4 KB on x86-64, though modern systems also support “huge pages” of 2 MB or 1 GB to cut down on translation overhead. The unit of mapping is the page, not the byte.

Each process has a page table: a tree-shaped data structure where the leaves are PTEs, each saying “virtual page N maps to physical page M, with these permissions (read/write/execute), and here’s a ‘present’ bit.” On x86-64 it’s a 4-level tree (5 levels on newer chips with larger address spaces).

On every memory access, the MMU does a page walk to translate the address. To avoid doing this for every load and store, there’s a hardware cache of recent translations called the TLB. TLB hits are essentially free; TLB misses cost dozens of cycles. This is why huge pages are interesting — fewer entries cover more memory.

When the MMU encounters a PTE with the present bit clear — the page isn’t currently in RAM — it raises a page fault. The kernel’s fault handler then decides what that fault means:

  1. Lazy allocation. First-touch on a freshly malloc’d page that was never written. Allocate a real page, zero it, fix up the PTE, restart the instruction. The program never knows.
  2. File-backed page-in. The page belongs to a memory-mapped file. Read it from disk, install it, restart.
  3. Swap-in. The page was evicted to swap. Read it back, install it, restart.
  4. Copy-on-write. Two processes share a page read-only after fork. One tries to write. The kernel allocates a fresh copy, points the writer’s PTE at it, restarts. Until that moment, fork was nearly free.
  5. Segfault. The address isn’t mapped at all, or the access violates permissions (write to read-only, execute on no-execute). Kernel sends SIGSEGV. The famous segfault is just “the page table said no.”

Cases 1–4 are invisible to the program. Case 5 is the only one users see, and even then only as “the program crashed.”

What you actually get from the indirection

Once translation exists, layering features onto it is almost free:

Show the seams

The deepest seam: virtual memory is the OS pretending it has more control than the hardware really gives it. The MMU is hardware; the kernel only gets a turn when the MMU faults. Almost every “OS feature” in this space is really “trick the MMU into faulting at a useful moment, then do work in the handler.” Page-on-demand, copy-on-write, swap, mmap, even some JIT and GC write barriers — all the same shape.

Going deeper