Paging & Page Tables

Paging is the mechanism that makes virtual memory work. It divides both virtual and physical memory into fixed-size chunks (pages), and maintains a translation table that maps virtual pages to physical ones.

Pages — 4KB Chunks

Why divide memory into pages? Managing memory byte-by-byte would be impossibly slow. Pages (4096 bytes on x86-64) are the minimum unit of allocation and protection. Every memory permission (read/write/execute) and every mapping applies to whole pages.

Page Tables — The Translation Map

x86-64 uses four-level page tables. A virtual address is split into five parts, each indexing into the next level of the table:

Virtual address (48 bits used): Bits 47-39: PGD index (Page Global Directory) Bits 38-30: PUD index (Page Upper Directory) Bits 29-21: PMD index (Page Middle Directory) Bits 20-12: PTE index (Page Table Entry) Bits 11-0: Offset within the 4KB page PGD → PUD → PMD → PTE → Physical page address + offset

Each process has its own PGD (top-level page table). CR3 register points to the current process's PGD. On context switch, CR3 is updated, instantly switching to the new process's address space.

The TLB — Translation Lookaside Buffer

Isn't walking 4 levels of tables for every memory access incredibly slow? Yes — without help. The TLB is a hardware cache inside the CPU that stores recent virtual→physical translations. A TLB hit means instant translation (no table walk). A TLB miss triggers the page table walk (handled by hardware on x86). TLB has limited entries — too many different pages = thrashing the TLB.

Context switches flush the TLB (or use Process Context IDs to avoid flushing). This is part of why context switching has overhead.

Page Faults — Three Types

TypeCauseActionCost
MinorPage in RAM but not mapped in page table yet (e.g., after fork() CoW)Update page table entryVery fast — no disk I/O
MajorPage not in RAM — must read from disk (swap or mmap'd file)Find page on disk, read into RAM, update tableSlow — disk latency (milliseconds)
SegfaultAccess to unmapped or protected addressSend SIGSEGV to processProcess may die
# Monitor page faults for a command /usr/bin/time -v my-program 2>&1 | grep "Page faults" # Major (I/O required) page faults: 12 # Minor (reclaiming) page faults: 4521