Computer Architecture Cheatsheet
Virtual Memory
Use this Computer Architecture reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Purpose of Virtual Memory
Virtual memory provides each process with its own private, contiguous address space, independent of physical DRAM layout. It enables:
- Protection — processes cannot read/write each other's memory
- Isolation — a crash in one process doesn't corrupt others
- Abstraction — programs can be larger than physical RAM (demand paging)
- Sharing — pages can be mapped read-only into multiple processes (shared libraries)
- Simplified linking — programs can assume fixed load addresses
Address Translation
Every memory access uses a virtual address (VA). The MMU translates it to a physical address (PA):
Virtual Address Page Table Physical Address
[ VPN | page offset ] ──────────────► [ PPN | page offset ]
(MMU)- VPN = Virtual Page Number
- PPN (or PFN) = Physical Page Number / Frame Number
- Page offset = unchanged; same in VA and PA
- Page size = 2^(offset bits). Common: 4 KB (12-bit offset), 2 MB, 1 GB (huge pages)
Address Space Example (x86-64, 4 KB pages)
64-bit VA: [ 16 sign-ext | 9 PML4 | 9 PDP | 9 PD | 9 PT | 12 offset ]
- 4-level page table on x86-64 (PML4 → PDPT → PD → PT → page) → 48-bit VA
- Bits 63:48 must equal bit 47 (canonical addresses — sign-extended); non-canonical access faults (#GP)
- 5-level paging (LA57): adds a PML5 level → 57-bit VA (128 PiB); shipping on Ice Lake+ servers, enabled per boot
- Each table has 2⁹ = 512 entries × 8 bytes = 4 KB per table
- ARM uses a similar structure (PGD → PUD → PMD → PTE)
Page Table Entry (PTE) Fields (x86-64)
| Bit(s) | Field | Meaning |
|---|---|---|
| 0 | Present (P) | 1 = page in physical memory |
| 1 | R/W | 0 = read-only, 1 = read/write |
| 2 | U/S | 0 = supervisor only, 1 = user accessible |
| 3 | Write-through | Cache write policy |
| 4 | Cache disable | Bypass cache (MMIO) |
| 5 | Accessed (A) | Set by hardware on any access |
| 6 | Dirty (D) | Set by hardware on write |
| 7 | PAT / Page size | If set at PD level → 2 MB huge page |
| 11:8 | Available | OS use |
| 51:12 | PPN | Physical page frame number |
| 62:59 | Protection key | 4-bit key (PKU/PKS), permission checked against PKRU |
| 63 | NX / XD | No-execute (prevents code execution) |
Page Fault Types
| Type | Cause | OS action |
|---|---|---|
| Demand page fault | Page not loaded yet (P=0) | Load page from disk, update PTE |
| Protection fault | Write to read-only page, or user access to kernel | SIGSEGV / segmentation fault |
| Copy-on-Write (CoW) | Write to shared read-only copy after fork() | Duplicate page, mark both writable |
| Minor fault | Page not mapped, but in page cache | Map the existing physical page |
| Major fault | Page must be read from disk | I/O required; high latency |
TLB (Translation Lookaside Buffer)
The page table walk is expensive (3–5 memory accesses for a 4-level table). The TLB is a small cache of recent VA→PA translations — L1 TLBs are fully or highly associative; larger L2 TLBs are set-associative (4–8-way) on modern cores.
TLB hit: ~1 cycle extra latency (parallel with cache lookup) TLB miss: ~20–50+ cycles (hardware page-table walk, PTW)
Typical TLB Parameters
| Level | Entries | Hit latency | Notes |
|---|---|---|---|
| L1 ITLB | 64–128 | 0–1 cycles | Instruction-only |
| L1 DTLB | 32–64 | 0–1 cycles | Data-only |
| L2 Unified TLB | 512–2048 | 5–10 cycles | Combined |
| Page-Walk Cache | — | — | Caches intermediate page-table entries |
TLB Shootdown
When the OS modifies a PTE (e.g., unmaps a page), it must invalidate any TLB entry holding that VA across all cores using that address space:
- OS modifies PTE
- OS sends IPI (Inter-Processor Interrupt) to other cores
- Each core executes
INVLPG <va>(x86) orTLBI(ARM) - Originating core waits for acknowledgements
- Flushing continues
TLB shootdowns are expensive — minimize mappings changes (mmap/munmap) in hot paths.
Page Replacement Policies
When a page fault occurs and physical memory is full, the OS must evict a page:
| Algorithm | Description | Optimal? | Notes |
|---|---|---|---|
| Optimal (OPT) | Evict the page not needed for longest future time | Yes | Theoretical; not implementable |
| LRU | Evict least recently used | Near-optimal | Expensive to implement exactly |
| Clock (second chance) | Circular list; evict first page with A=0 | — | Classic UNIX/Mach; PostgreSQL's buffer pool (clock-sweep) |
| LRU-K | Use Kth most recent access | — | More scan-resistant; LRU-2 used in SQL Server's buffer manager |
| NRU (Not Recently Used) | Combine A and D bits into 4 classes | — | Cheap; approximate LRU |
Linux does not use classic clock — it approximates LRU with two lists (active/inactive) per memory cgroup, promoting/demoting pages between them (multi-gen LRU since 6.1).
NRU Classes
| Class | Accessed | Dirty | Preference to evict |
|---|---|---|---|
| 0 | 0 | 0 | First (best) |
| 1 | 0 | 1 | Second |
| 2 | 1 | 0 | Third |
| 3 | 1 | 1 | Last (worst) |
Huge Pages
| Size | x86-64 | ARM | Benefit |
|---|---|---|---|
| 4 KB | Standard | Standard | Fine-grained control |
| 2 MB | Large page (PD entry) | 2 MB block | Fewer TLB entries for same range |
| 1 GB | Huge page (PDP entry) | 1 GB block | Minimal TLB pressure |
Linux: Transparent Huge Pages (THP) automatically promotes 4 KB pages to 2 MB when contiguous. hugetlbfs for explicit huge-page allocation.
Memory Protection
| Mechanism | Description |
|---|---|
| Read/Write/Execute bits | Per-page permissions in PTE |
| Supervisor bit | Kernel vs user access control |
| NX bit (no-execute) | Prevents executing data pages (defeats shellcode) |
| SMEP / SMAP | Supervisor cannot execute/access user pages (x86) |
| ASLR | Randomize base addresses of stack, heap, libraries |
| PIE (Position Independent Executable) | Text relocatable; ASLR can randomize code |
Segmentation (legacy)
x86 originally used segments (base + limit per logical address region) before paging. Modern x86-64 uses flat segmentation (all segments base=0, limit=2⁶⁴) — paging is the real protection mechanism. Segments still exist for fs and gs as thread-local storage pointers.
Copy-on-Write (CoW) in fork()
Parent calls fork(): - Child gets a copy of parent's page table - All pages marked read-only in both parent and child - Physical pages are shared First write by either process: - Protection fault - OS allocates new page, copies content - Updates faulting process's PTE to new page, marks R/W - Other process still references original (now also R/W)
CoW makes fork() + exec() extremely cheap — only modified pages are actually copied.