Virtual Memory Visualized: Pages, Page Tables and Address Translation
Follow a virtual address through the TLB and page table to physical memory, including page faults, protection, and the limits of the model.
Address Translation Visualizer
A process normally works with virtual addresses, while the operating system and hardware cooperate to map those addresses to physical memory. This indirection gives each process a useful address-space abstraction, supports protection, and lets the OS manage physical memory without requiring an application's layout to match RAM exactly.
The diagrams here deliberately use a tiny single-level page table and decimal addresses. Real platforms may use multi-level or other table structures, several page sizes, architecture-specific caches, and policies that change across operating systems. The arithmetic is real; the scale and organization are simplified.
A process sees a virtual address space
Each process conceptually has its own virtual address space. An address such as 2500 identifies a location in that process's view, not a universal byte of physical RAM. Another process can use the same numeric virtual address and map it to a different physical frame—or have no valid mapping there at all.
This clarifies the diagrams in Stack vs Heap. Stack frames, heap allocations, executable code, and static data are normally discussed as regions in a process's virtual address space. A heap allocation need not be physically adjacent to another allocation, and a neat source-level diagram is not a physical RAM map.
The OS establishes mappings and permissions. Hardware performs address translation during memory access using architecture-defined structures, while privileged OS code handles events such as missing or forbidden mappings.
Pages and frames
Paging divides the two sides into fixed-size units:
- virtual address space is divided into pages;
- physical memory is divided into frames.
A mapping associates one virtual page with one physical frame. The page and frame have the same size for that mapping, so the position inside the page can be carried across unchanged.
This tutorial often uses a 1,024-byte page because the arithmetic is visible. A 4 KiB page is common on many systems, but it is not universal; architectures may support multiple sizes, and the active choice can vary.
Split the virtual address
Conceptually, a virtual address contains two parts:
virtual page number | offset within that pageFor page size P and virtual address V:
page = floor(V / P)
offset = V mod PThe virtual page number selects a mapping. The offset selects the byte within that page. Translation replaces the virtual page number with a physical frame number while preserving the offset.
For a deliberately small system:
page size = 1024 bytes
virtual address = 2500
page = floor(2500 / 1024) = 2
offset = 2500 mod 1024 = 452The split does not access physical memory yet. It identifies which mapping is needed.
Page tables hold mappings
A page table describes virtual-page mappings and associated state for a process. A simplified portion might be:
Virtual page 0 -> Physical frame 3
Virtual page 1 -> Physical frame 4
Virtual page 2 -> Physical frame 7
Virtual page 3 -> not presentLooking up page 2 returns frame 7. Translation then combines the frame base with the unchanged offset:
physical address = frame x page size + offset
= 7 x 1024 + 452
= 7620The data in frame 7 at offset 452 corresponds to this process's virtual address 2500. A different process needs its own mapping decision even if it also asks for address 2500.
Real page-table entries commonly carry more than a frame number: presence state, permissions, accessed or dirty state, and architecture-specific control bits. Table structures are optimized so the OS does not need one enormous flat array for every theoretical virtual page.
The TLB avoids repeated table walks
Consulting page-table structures for every instruction fetch and data access would be expensive. Processors therefore use a Translation Lookaside Buffer, or TLB, to cache recent virtual-page translations.
On a TLB hit, the processor obtains the frame mapping from this cache. On a miss, it performs the platform's page-table lookup. A valid result can populate the TLB so later accesses to that page avoid another walk. A TLB miss is not a page fault: the translation may be absent from the cache while perfectly valid in the page table.
This is another example of locality. Programs often access the same pages repeatedly or touch nearby addresses within one page, making recent translations useful. The CPU cache tutorial applies related locality principles to cached data rather than address mappings.
What a page fault means
If the referenced virtual page is not currently present in the required form, hardware raises a page fault and transfers control to the operating system. The OS examines the cause.
A demand-paging fault can be normal. The OS may locate the page's backing data, obtain a frame, load or initialize the contents, update the page table, and retry the interrupted instruction. If the data is already in memory through another mechanism, handling need not involve storage I/O. A copy-on-write fault may create a private writable copy. Other valid faults allocate a fresh zero-filled page.
An invalid address or forbidden access is different. If no legal mapping can satisfy the operation—writing to a read-only page, executing a non-executable page, or accessing outside a permitted region—the OS reports a protection failure to the process rather than simply loading data and continuing.
Therefore:
- a page fault does not automatically mean disk access;
- a page fault does not automatically mean a program bug;
- some faults are expected mechanisms, while others represent invalid operations.
The visualizer's page-fault scenario maps a page into one free frame and retries. That is one conceptual successful path, not a simulation of OS timing, eviction, storage, or every reason a fault can occur.
Protection and isolation
Mappings commonly include permissions such as readable, writable, and executable. The hardware checks access against them. Code can be readable and executable without being writable; data can be readable and writable without being executable. Exact policies depend on the platform and program.
Because each process has its own address-space context, the same virtual page number can resolve differently across processes. Ordinary application code cannot create arbitrary mappings into another process. This contributes to process isolation: access is mediated by mappings and privileges rather than by treating every pointer as a raw physical address.
Virtual memory is one layer of isolation, not a complete security guarantee. Kernel defects, privileged debugging interfaces, shared-memory mappings, and deliberately shared files introduce different rules.
Locality, working sets, and pressure
Temporal locality means recently used data is likely to be used again. Spatial locality means nearby data is likely to be used soon. Both help paging: repeated accesses concentrate on a working set of pages rather than uniformly touching the whole address space.
If a workload's actively needed pages fit comfortably in available memory, most accesses can use present mappings. Under pressure, the OS may reclaim frames and preserve page contents in backing storage where appropriate. Later access can fault and require the page again. Policies differ substantially, so “the OS swaps this exact object” is usually too literal a mental model.
Backing storage can support anonymous memory, mapped files, hibernation, or platform-specific compression and paging strategies. Not all virtual pages need disk backing, and not every present physical frame corresponds to a private application allocation.
Virtual memory is not RAM plus disk
Several shortcuts obscure more than they explain:
- Virtual memory is not simply RAM plus disk. It is an address translation and protection abstraction; backing storage is one possible mechanism within it.
- A virtual address is not a physical address. It must be interpreted through the active address-space mapping.
- A page fault is not automatically an error. Demand paging and copy-on-write intentionally use faults.
- Equal virtual addresses do not imply shared storage. Different processes can map them differently.
- Stack and heap diagrams are conceptual virtual layouts. Compilers, runtimes, allocators, and the OS determine concrete placement.
Costs and boundaries
Translation has costs: TLB capacity is finite, page-table walks consume memory accesses, faults enter the OS, and moving page contents can be expensive. Larger pages can cover more memory per translation but may waste space or make placement less flexible. Smaller pages provide finer granularity but increase mapping metadata and TLB pressure.
Those tradeoffs explain why one universal layout would be inadequate. For application engineering, the durable model is page number plus offset, cached translation when available, page-table lookup on a TLB miss, and OS handling when the mapping cannot immediately satisfy the access.
Step through all three visualizer scenarios and keep the distinctions sharp: TLB hit, TLB miss with a valid mapping, and page fault are three different paths.
Related Tutorials
A careful conceptual model of call frames, dynamic allocation, ownership, lifetime, and what managed runtimes can change.
See how cache lines, locality, access order, and finite capacity make two algorithms with the same Big O behave differently on real hardware.
Recursion explained as ordinary function calls, pending stack frames, base cases, and a controlled return journey.