Course outline · 0% complete

0/28 lessons0%

Course overview →

Virtual memory: every process gets its own map

lesson 4-4 · ~12 min · 14/28

The grand illusion behind process isolation

Three lessons so far have leaned on one promise: each process gets private memory and cannot touch anyone else's, in lessons 1-3, 3-1, and 4-1. This lesson shows the machinery that keeps the promise.

You will meet its symptoms directly, in a machine that crawls to a halt when RAM runs out, the word segfault in a crash log, and memory dashboards showing virtual sizes far bigger than the RAM installed.

The trick is called virtual memory. A process never sees real RAM addresses. Every address in a program, meaning every variable, every stack frame, and every heap object, is a virtual address, a made-up number in the process's own private numbering that starts at zero.

The OS keeps a page table per process, a map from the process's virtual addresses to the physical RAM locations actually holding the data. The CPU translates every single memory access through that map, in hardware, automatically.

To keep the map small, memory is managed in fixed-size chunks called pages, typically 4 KB. The table says that virtual page 0 lives in physical frame 7, virtual page 1 lives in physical frame 2, and so on. Two consequences fall out immediately:

  • Isolation for free. Process A's page table simply contains no entry pointing at process B's frames, so A cannot even name B's memory. That is the enforcement mechanism behind everything unit 3 promised.
  • Two processes can use the same virtual address for different data, which is why every process can believe it owns a clean, empty address space starting at zero.
process Aprocess Bphysical RAMpage tablespage 0page 1page 0page 1frame 0frame 1frame 2frame 3same virtual page numbers, different physical frames — neither process can name the other's memory
Each process numbers its own pages from zero, and its page table maps them to scattered physical frames.

A page table you can read

Virtual addresses split into a page number, which chunk, and an offset, the position inside that chunk.

PAGE_SIZE = 100
page_table = {0: 700, 1: 300, 2: 900}

def translate(virtual_address):
    page = virtual_address // PAGE_SIZE
    offset = virtual_address % PAGE_SIZE
    return page_table[page] + offset

for addr in [0, 42, 150, 250]:
    print("virtual", addr, "-> physical", translate(addr))

Output

virtual 0 -> physical 700
virtual 42 -> physical 742
virtual 150 -> physical 350
virtual 250 -> physical 950

Virtual address 150 is page 1, from 150 // 100, at offset 50, from 150 % 100. Page 1 maps to physical 300, so the answer is 350.

The virtual addresses are neat and contiguous while the physical locations are scattered, and the process never knows the difference. Real hardware performs exactly this split, with 4096-byte pages and in silicon, on every memory access.

Page faults and swapping, when the map has a hole

A process can touch a virtual page with no entry in the table. The hardware then stops mid-instruction and hands control to the kernel, and that event is a page fault. The kernel decides what it means.

Legal but not loaded. The page exists but its data is currently on disk. The kernel loads it into a free frame, updates the table, and resumes the process as if nothing happened. The process never notices beyond the time it took.

Illegal. The process had no right to that address, so the kernel kills it. This is the segmentation fault from lesson 4-2, finally with its full mechanism visible: a page-table lookup that came up empty-handed.

Fault kindKernel response
page is on diskload it, update the table, resume
page is not the process's at allterminate with a segfault

The on-disk case enables swapping. When RAM fills up, the kernel evicts pages that have not been used recently to a reserved area of disk called swap space, freeing frames for whoever needs them now.

That is why a machine out of RAM does not instantly die but instead crawls. Pages keep faulting back and forth between RAM and a disk that is a thousand times slower, which is lesson 1-1's ratios turned into a symptom. Engineers call the worst version thrashing, where the machine spends all its time moving pages and none doing work.

When a dashboard shows a process's virtual size far above physical RAM, virtual memory is what makes that legal.

Teaching the translator about page faults

A missing page becomes a reported fault instead of a KeyError.

PAGE_SIZE = 100
page_table = {0: 700, 1: 300, 2: 900}

def translate(virtual_address):
    page = virtual_address // PAGE_SIZE
    offset = virtual_address % PAGE_SIZE
    if page not in page_table:
        return "page fault: page " + str(page) + " is not in RAM"
    return "physical " + str(page_table[page] + offset)

print(translate(42))
print(translate(340))

Output

physical 742
page fault: page 3 is not in RAM

Virtual address 340 is page 3, and the table only holds pages 0, 1, and 2, so the membership check catches it. str(page) puts the number into the message.

Real hardware behaves the same way at this point, with one important difference. The check is not an if in software, it is a hardware lookup that traps into the kernel, which is why a fault costs a context switch rather than a comparison.

The same address in two processes

Processes A and B can both store a variable at address 5000 with no collision, because 5000 is a virtual address in each process's private numbering and each page table maps it to a different physical frame.

Virtual addresses are per-process fictions. Each table translates its own address 5000 to a different physical frame, so the same number names different real memory.

ProcessVirtual addressPhysical frame
A5000one frame
B5000a different frame

This is also exactly why process isolation holds. A's table simply has no path to B's frames, so the isolation is not a check that could be bypassed, it is an absence of any route at all.

Naming the eviction of cold pages to disk

Moving not-recently-used pages out to a reserved area of disk to free frames is called swapping, also described as paging out.

The kernel evicts cold pages to swap space on disk and reloads them on a page fault. It keeps the machine alive past physical RAM, at disk speed, which is roughly a thousand times slower.

TermRefers to
swap spacethe reserved disk area
swapping or paging outevicting pages into it
thrashingswapping so heavily that no work gets done

The disk-speed penalty is why heavy swapping feels like the computer is wading through mud, and it is why a machine out of RAM crawls instead of dying outright.