PGDPML4512 GiBpoints to a PUD; not a 512 GiB page
512 × 1 GiBA concise, interactive mental model of how processes, the MMU, the kernel, RAM, and storage work together.
Each process sees a private, protected address space—even while physical RAM is shared by the whole system.
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.
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.
0x4000○0x5000○0x6000●0x7000○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.The address stays virtual until the MMU translates it. Most translations are remembered by the TLB.
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.
The MMU turns each virtual address into a physical address. A TLB hit skips the page-table walk entirely.
Follow the amber path through each table. Only the active entry at each level matters.
Blue fields have already been consumed by the page-table walk. The outlined field is the current step; the page offset is applied last.
0x0000_7F4B_12A0_03F80x0000Canonical prefixA 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.
2⁴⁷ bytes of ordinary per-process user virtual address space on four-level Linux.
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.
bits 47–39 → entry 254selected entry → PUDbits 38–30 → entry 300selected entry → PMDbits 29–21 → entry 149selected entry → PTEbits 20–12 → entry 0selected entry → physical frameoffset 0x3F8selects one byteEach 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 DirectoryPML4 · Page Map Level 4PUDPage Upper DirectoryPDPT · Page Directory Pointer TablePMDPage Middle DirectoryPD · Page DirectoryPTEPage Table EntryPT · Page TablePGDPML4512 GiBpoints to a PUD; not a 512 GiB page
512 × 1 GiBPUDPDPT1 GiBor directly maps a 1 GiB huge page
512 × 2 MiBPMDPD2 MiBor directly maps a 2 MiB huge page
512 × 4 KiBPTEPT4 KiBmaps 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.
0x0000_0000_0000_00000x0000_7FFF_FFFF_FFFFCommonly user spaceBits 63–48 are 0x00000x0000_8000_0000_00000xFFFF_7FFF_FFFF_FFFFNot valid addresses in ordinary 48-bit modeUpper bits do not match bit 470xFFFF_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.
A hit jumps straight to the saved physical frame. A miss walks all four page-table levels.
The hierarchy stays sparse: unused address ranges need no lower-level tables, avoiding the enormous cost of a flat table.
Allocation reserves an address range. Physical memory usually arrives only when the page is first touched.
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.
The kernel first decides whether the address belongs to a valid region. Only then can it allocate a frame.
0x55A3_C2F0_0000The kernel reclaims a frame before it can satisfy the fault.
A = 1Recently accessedGive it another chanceHot ↔ coldPages age when they stop being reusedCold candidatePrefer the cheapest safe page to freeFor 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.
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.
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.
Once pages can be remapped on demand, the kernel can share work and delay copies until they are truly needed.
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.
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.
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 bytesYour code reads from: the user buffer filled by read().
mmap()Maps the cached pagesYour code reads from: the mapped address. First access can fault while the kernel installs the page-table entry.
MAP_PRIVATEPrivate copy-on-write viewReads 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 viewWrites 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.
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.
Memory may look flat, but access cost depends on how many pages, translations, cache lines, and physical links the workload touches.
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.
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.
Changing mappings can interrupt other CPU cores to flush stale translations.
A page is fastest when it lives near the CPU that uses it.
Start with what is mapped, then ask what is resident, whether faults touch storage, and whether hardware topology is getting in the way.
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.
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 AreaRSSResident Set SizePSSProportional Set Size/proc/<pid>/mapspmap -x <pid>/proc/<pid>/smapsRSS (resident) vs PSS (shared proportion)perf stat -e page-faults,major-faultsmajor faultsvmstat 1/proc/pressure/memoryperf stat -e dTLB-load-missespage-walk eventsnumastat -p <pid>/proc/<pid>/numa_mapsPrivate address spaces → page tables → TLB → physical frames → files or swap.