Virtual memory,
made visible.

A concise, interactive mental model of how processes, the MMU, the kernel, RAM, and storage work together.

Process AVirtual address space
Process BVirtual address space
Page table A
Page table B
MMUTranslates every access
Physical RAM
01234567
StorageFiles and swap
ProcessMmuKernelPhysical memoryStorage

1. Every process gets its own map

Each process sees a private, protected address space—even while physical RAM is shared by the whole system.

Reading noteIn plain English

A program does not normally work with raw locations in RAM. It produces virtual addresses inside its own private address space. The processor’s memory-management hardware translates those addresses before RAM is accessed, using page tables maintained by the operating system.

This indirection gives every process a clean, protected map even though the underlying RAM is shared and fragmented. The same virtual address can refer to completely different physical frames in two processes, and a process cannot reach another process’s memory unless the kernel deliberately creates a shared mapping.

Hold onto this: The address space is private; the physical memory underneath it is shared.

Chapter guideOptional context and legend

What’s happening

Select a region in the address-space map. The active virtual page follows its page-table entry to a physical frame.


Adjacent virtual pages do not need to be adjacent in RAM. The mapping hides that fragmentation.

ProcessYour program
MMUHardware translator
KernelMakes memory decisions
Physical memoryActual RAM frames
StorageFiles or swap
Takeaway:Virtual addresses are private labels. Page tables connect them to real physical frames.
Process AVirtual address space
Address width
48-bit canonical
User space
lower half
Permissions
R-- / RW-
High addressesLow addresses
Page table
0x4000
0x5000
0x6000
0x7000
Physical RAM
012345678
Mapped files

Shared libraries and memory-mapped files live here. Pages are pulled in from storage on demand.

The same virtual address in another process can map to a different frame.

2. Follow one address

The address stays virtual until the MMU translates it. Most translations are remembered by the TLB.

Reading noteIn plain English

With the common four-level x86-64 layout, 48 bits participate in translation: four 9-bit page-table indexes plus a 12-bit offset for a 4 KiB page. The remaining upper bits must make the address canonical. Multiple table levels keep the structure sparse, so unused address ranges consume little bookkeeping memory.

Walking those tables for every load and store would be expensive. The TLB is a small hardware cache of recent translations. A TLB hit supplies the physical frame immediately; a miss makes the MMU walk the page tables, then remember the result for later accesses.

Hold onto this: Translation happens on every memory access, but the TLB makes most translations nearly invisible.

Chapter guideOptional context and legend

What’s happening

Address translation

The MMU turns each virtual address into a physical address. A TLB hit skips the page-table walk entirely.


How to read this view

Follow the amber path through each table. Only the active entry at each level matters.

ProcessYour program
MMUHardware translator
KernelMakes memory decisions
Physical memoryActual RAM frames
StorageFiles or swap
Interactive address breakdownClick a field to jump to that stage

Blue fields have already been consumed by the page-table walk. The outlined field is the current step; the page offset is applied last.

Virtual address0x0000_7F4B_12A0_03F8
bits 63–480x0000Canonical prefix
x86-64 · four-level paging · 4 KiB pages

Why a 64-bit pointer usually uses 48 translated bits

4 × 9 index bits+12 offset bits=48 translated bits

A page table contains 512 entries, so each level needs 9 index bits (2⁹ = 512). Four levels contribute 36 bits, and a 4 KiB page needs 12 offset bits (2¹² = 4096). Together they identify 2⁴⁸ byte positions. Canonical addressing divides those positions into two equal 2⁴⁷-byte halves instead of one continuous range in the middle of the 64-bit number line.

Bits 63–48 are not another page-table index. In four-level mode they must repeat bit 47: all zeroes for the lower half, or all ones for the upper half. Addresses obeying that rule are canonical. Using a non-canonical address causes the CPU to reject it before a normal page-table lookup can succeed.

bit 47 = 0Lower canonical half128 TiB

2⁴⁷ bytes of ordinary per-process user virtual address space on four-level Linux.

bit 47 = 1Upper canonical half128 TiB

Architecturally valid high addresses, conventionally used for shared kernel mappings.

Why people say “128 TiB virtual address space”: they usually mean the lower user half available to one process. Counting both canonical halves gives 256 TiB; the enormous range between them is non-canonical and cannot be used in ordinary 48-bit mode.

CR3points to the top-level table
PGDPML4512 entriesbits 47–39 → entry 254selected entry → PUD
PUDPDPT512 entriesbits 38–30 → entry 300selected entry → PMD
PMDPD512 entriesbits 29–21 → entry 149selected entry → PTE
PTEPT512 entriesbits 20–12 → entry 0selected entry → physical frame
4 KiB frameoffset 0x3F8selects one byte
ONE SELECTED ENTRY

How large a chunk does it cover?

Each table has 512 entries, so moving one level upward multiplies the covered range by 512. Coverage is not always page size:an entry normally points to the next table, unless it is a permitted leaf.

PGDPage Global Directory
x86-64: PML4 · Page Map Level 4
PUDPage Upper Directory
x86-64: PDPT · Page Directory Pointer Table
PMDPage Middle Directory
x86-64: PD · Page Directory
PTEPage Table Entry
x86-64: PT · Page Table
PGDPML4512 GiB

points to a PUD; not a 512 GiB page

512 × 1 GiB
PUDPDPT1 GiB

or directly maps a 1 GiB huge page

512 × 2 MiB
PMDPD2 MiB

or directly maps a 2 MiB huge page

512 × 4 KiB
PTEPT4 KiB

maps one ordinary 4 KiB page

Huge-page exceptions: on x86-64, a PMD can stop the walk and map one 2 MiB page, while a PUD can map one 1 GiB page. The four-level PGD still points onward—there is no 512 GiB leaf page. With five-level paging, a PGD/PML5 entry covers 256 TiB and selects a P4D/PML4 table; it does not map a 256 TiB page directly.

Inside the selected 64-bit leaf PTE

The frame number is only part of the entry

A PTE also tells the CPU whether the page exists, who may use it, and which operations are allowed. The example below describes a present, user-readable, read-only, non-executable page.

bit 63NX1bits 62–52OS / reservedbits 51–12Physical frame number0x3F7C5bits 11–7OS / page controlsbit 6D0bit 5A1bits 4–3Cachebit 2U/S1bit 1R/W0bit 0P1
PPresent0 means translation stops with a page fault.
R/WRead / write0 is read-only; 1 permits writes.
U/SUser / supervisor0 restricts access to the kernel; 1 permits user mode.
NXNo execute1 prevents this page from containing executable instructions.
AAccessedThe CPU sets it after the entry participates in a translation.
DDirtyThe CPU sets it after a write reaches the mapped page.
Lower canonical half · bit 47 = 00x0000_0000_0000_00000x0000_7FFF_FFFF_FFFFCommonly user spaceBits 63–48 are 0x0000
Non-canonical hole0x0000_8000_0000_00000xFFFF_7FFF_FFFF_FFFFNot valid addresses in ordinary 48-bit modeUpper bits do not match bit 47
Upper canonical half · bit 47 = 10xFFFF_8000_0000_00000xFFFF_FFFF_FFFF_FFFFCommonly kernel spaceBits 63–48 are 0xFFFF

“Low” and “high” are conventions. The CPU enforces canonical form; the operating system decides how those valid ranges are assigned. Linux normally places per-process user mappings low and shared kernel mappings high.

Modern systems may support five levels. LA57 adds another 9-bit index and translates 57 bits. Canonical addresses then repeat bit 56 through bits 63, although Linux generally keeps ordinary allocations in the familiar lower range unless software requests wider addresses.

Architecture references: Linux x86-64 memory map, five-level paging, and the Intel architecture manuals.

Interactive translation path

Choose what the TLB finds

A hit jumps straight to the saved physical frame. A miss walks all four page-table levels.

Page-table walkCPU issues load
CPULoad byte
TLBMiss
PGDPML4 · level 1
PUDPDPT · level 2
PMDPD · level 3
PTEPT · level 4
Physical framePFN 0x3F7C5
+ 0x3F8same offset
Takeaway:The page number changes. The 12-bit offset does not.
Why four levels?

The hierarchy stays sparse: unused address ranges need no lower-level tables, avoiding the enormous cost of a flat table.

3. Touch a page

Allocation reserves an address range. Physical memory usually arrives only when the page is first touched.

Reading noteIn plain English

A reserved address range does not imply that every page already occupies RAM. On first access, the page-table entry may say “not present.” The CPU then pauses the process and asks the kernel to resolve a page fault. If the address belongs to a valid virtual memory area (VMA)—one continuous region with a shared mapping and permission policy—the kernel can allocate a frame or load the required file page and resume the instruction.

A minor fault can be resolved without storage I/O; a major fault must wait for a file or swapped page. If the address is outside every valid region, or the requested access violates its permissions, the kernel cannot repair it and reports a segmentation fault instead.

Hold onto this: A page fault is a normal request for help; a segmentation fault is a rejected request.

Chapter guideOptional context and legend

What’s happening

Step 3 of 6 — Check the virtual memory area (VMA)

The kernel first decides whether the address belongs to a valid region. Only then can it allocate a frame.

VMA = allowed regionA continuous range with one mapping and permission policy.PTE = current realityWhat is mapped right now.
ProcessYour program
MMUHardware translator
KernelMakes memory decisions
Physical memoryActual RAM frames
StorageFiles or swap
First write after malloc0x55A3_C2F0_0000
Minor faultNo disk I/O—bookkeeping only.
Major faultData must come from a file or swap.

What if RAM is full?

The kernel reclaims a frame before it can satisfy the fault.

Clean file page: drop itReload it from the file later.
Dirty file page: write it backPersist changes, then reclaim.
Anonymous page: move it to swapSave private data, then free the frame.
How the victim is chosen

Keep hot pages; reclaim cold ones

A = 1Recently accessedGive it another chanceHot ↔ coldPages age when they stop being reusedCold candidatePrefer the cheapest safe page to free
1 · Observe referencesSample the Accessed bit

For a mapped page, the CPU sets its page-table entry’s A bit when it is used. During a scan, the kernel can clear it and later check whether another access set it again.

2 · Age repeatedlyRank relative recency

Pages that keep being referenced stay active or move to a younger generation. Pages missed by repeated samples drift toward inactive lists or older generations.

3 · Filter candidatesBalance age against cost

Unevictable pages are skipped. Clean file pages are cheap to drop; dirty or anonymous pages first need writeback or swap space.

“Stale” is not a fixed timeout. It means less recently reused than other eligible pages under the current memory pressure. Linux uses approximate recency—active/inactive lists or, when enabled, multiple LRU generations—because trapping every load and store would be far too expensive.

kswapd normally reclaims in the background. If it cannot keep up, an allocating process may enter direct reclaim and pause. Refaults tell the kernel that it evicted useful data too aggressively; repeatedly evicting pages that are needed again is thrashing.

Takeaway:A page fault is a request for help. A segmentation fault is the kernel refusing it.

4. The same machinery, useful tricks

Once pages can be remapped on demand, the kernel can share work and delay copies until they are truly needed.

Reading noteIn plain English

Because mappings can be changed one page at a time, the kernel can delay expensive work. After fork, parent and child initially share the same physical pages as read-only. Only the first writer faults; the kernel copies that page and gives the writer a private, writable mapping. This is copy-on-write.

A memory-mapped file uses the same machinery to connect part of a process’s address space to pages in the file cache. Mappings can be anonymous or file-backed, and private or shared. With mmap(), that second choice is expressed as MAP_PRIVATE or MAP_SHARED: it determines whether writes stay private or become visible through the shared mapping.

Hold onto this: Sharing, copying, and file access are different policies built on the same page-table mechanism.

Chapter guideOptional context and legend

What’s happening

Copy-on-write

A write to a shared read-only page becomes a controlled fault. The kernel copies only that page and updates one mapping.


The same mechanisms—permissions, faults, and remapping—create several useful higher-level behaviors.

ProcessYour program
MMUHardware translator
KernelMakes memory decisions
Physical memoryActual RAM frames
StorageFiles or swap
Parent page table
Read / write
Original framesNo page data copied yet.
Takeaway:fork is cheap because pages are shared until someone writes.
File access

One page cache, two paths to your process

If the file pages are not cached yet, the kernel first loads them from storage. The difference comes after the page cache.

read()Copies the bytes
One extra copy
File dataStorage
Kernel-managedPage cache
copy bytes
Separate allocationUser buffer

Your code reads from: the user buffer filled by read().

mmap()Maps the cached pages
No buffer copy
File dataStorage
Kernel-managedPage cache
map pages
Process-visibleMapped addresses

Your code reads from: the mapped address. First access can fault while the kernel installs the page-table entry.

Takeaway:Both methods use the page cache. read() copies cached bytes into a separate buffer; mmap() maps those cached pages into the process address space.

Two questions classify a mapping

AnonymousWhere do the bytes come from?File-backed
PrivateWho can observe writes?Shared
MAP_PRIVATEPrivate copy-on-write view

Reads can share the same physical pages. On the first write, the kernel gives that process a private copy. Other mappings do not see the change, and a file-backed mapping does not write it to the file.

Think: “start together, diverge on write.”
MAP_SHAREDOne shared view

Writes are visible to other processes mapping the same region. For a file-backed mapping, dirty data is carried through to the file; msync() can request precise synchronization.

Think: “changes belong to the shared object.”

Independent choices: anonymous versus file-backed says where bytes originate; MAP_PRIVATE versus MAP_SHARED says what writes mean. See the Linux mmap(2) manual.

5. Locality is the real performance feature

Memory may look flat, but access cost depends on how many pages, translations, cache lines, and physical links the workload touches.

Reading noteIn plain English

Virtual memory is not uniformly fast. Sequential access tends to reuse translations and cache lines, while scattered access touches more pages and pushes useful entries out of the TLB and CPU caches. Performance usually depends on the active working set, not the headline size of the allocation.

Huge pages let one TLB entry cover more memory, but they are not a universal cure. Mapping changes can trigger cross-core TLB shootdowns, and on NUMA systems a page may be physically far from the CPU using it. These are separate costs and should be measured separately.

Hold onto this: Good locality helps page tables, the TLB, CPU caches, prefetchers, and NUMA placement at once.

Chapter guideOptional context and legend

What’s happening

Sequential access walks through nearby pages. The CPU, TLB, and caches can predict and prepare.


Random probes jump across the allocation. Useful translations and cache lines are displaced before reuse.

ProcessYour program
MMUHardware translator
KernelMakes memory decisions
Physical memoryActual RAM frames
StorageFiles or swap
Compare access patterns

How access order changes cost

Access order
100101102103104105106107
Nearby pages are reusedThe next address is easy to predict, so translations and cache data stay useful.
Page footprintCompact
TLB reuseHigh
PrefetcherHelps

Page size

0123456789101112131415
One TLB entry covers 4 KiB.Huge pages reduce translation overhead but need large contiguous physical blocks.

Two costs hidden by the abstraction

TLB shootdowns

Changing mappings can interrupt other CPU cores to flush stale translations.

Core 0KernelCore 1Core 2
NUMA placement

A page is fastest when it lives near the CPU that uses it.

Socket 0Node 0 RAM
Takeaway:Keep the hot working set compact, reuse pages, and measure before reaching for huge pages.

6. Diagnose from the outside in

Start with what is mapped, then ask what is resident, whether faults touch storage, and whether hardware topology is getting in the way.

Reading noteIn plain English

Start by separating the virtual map from physical residency. A large mapped range may be mostly untouched and therefore cheap. Resident Set Size (RSS) shows what is currently in RAM; Proportional Set Size (PSS) divides shared pages among the processes using them. Compare both, then inspect minor and major faults to see whether storage has entered the hot path.

If pressure is high, check reclaim, swap activity, and memory-pressure stalls. If storage is quiet but the workload is still slow, look at TLB misses and NUMA placement. Diagnose in this order so that a mapping problem, a capacity problem, and a hardware-locality problem do not get mistaken for one another.

Hold onto this: Map → residency → storage → translation → topology.

Chapter guideOptional context and legend

What the signals mean

Large mapped area (VMA), low resident memory (RSS)Usually normal lazy allocationHigh major faultsStorage or swap is on the hot pathSwap in + swap outPossible thrashingHigh TLB misses, low major faultsTranslation—not storage—is the bottleneck
Don’t guess.Check the signals in order before changing anything.

Three memory terms, in plain language

They answer different questions: what the process may address, what is in RAM now, and what share of RAM fairly belongs to it.

VMAVirtual Memory Area
One continuous address range with the same permissions and backing. It describes the process’s map—not how much RAM is currently used.
RSSResident Set Size
Pages from this process that are currently in RAM. Shared pages are counted in full for every process, so totals can double-count.
PSSProportional Set Size
RSS adjusted for sharing: each shared page is divided among its users. It better estimates this process’s fair share of RAM.

A practical investigation order

1What is mapped?/proc/<pid>/mapspmap -x <pid>
2What is actually resident?/proc/<pid>/smapsRSS (resident) vs PSS (shared proportion)
3Are faults touching storage?perf stat -e page-faults,major-faultsmajor faults
4Is the system reclaiming aggressively?vmstat 1/proc/pressure/memory
5Is translation expensive?perf stat -e dTLB-load-missespage-walk events
6Is placement uneven?numastat -p <pid>/proc/<pid>/numa_maps

Keep this picture in your head

Private address spaces → page tables → TLB → physical frames → files or swap.

Private address spacesPage tablesTLBPhysical framesFiles or swap