Servicing a fault assumed a free frame was waiting. Suppose none is.
21.4 What If Memory Is Full?
Then the OS must first page out one or more residents to make room β and choosing the victim is the page-replacement policy page-replacement policy The decision of WHICH page to kick out when memory is full. Choosing badly runs programs at disk speed β 10,000β100,000Γ slower β which is why it gets its own chapter. defined in ch. 21 β open in glossary , a decision with terrifying stakes: evict the wrong page and a program runs at disk-like speeds instead of memory-like speeds β 10,000 to 100,000Γ slower. That number is why the policy gets the entire next chapter; for now itβs enough that one exists, built on this chapterβs mechanisms.
21.5 Page Fault Control Flow
Everything the hardware can encounter on a reference, in one place β so when someone asks βwhat happens when a program fetches data from memory?β, you have the full answer. The hardware side (Figure 21.2):
VPN = (VirtualAddress & VPN_MASK) >> SHIFT
(Success, TlbEntry) = TLB_Lookup(VPN)
if (Success == True) // TLB Hit
if (CanAccess(TlbEntry.ProtectBits) == True)
Offset = VirtualAddress & OFFSET_MASK
PhysAddr = (TlbEntry.PFN << SHIFT) | Offset
Register = AccessMemory(PhysAddr)
else
RaiseException(PROTECTION_FAULT)
else // TLB Miss
PTEAddr = PTBR + (VPN * sizeof(PTE))
PTE = AccessMemory(PTEAddr)
if (PTE.Valid == False)
RaiseException(SEGMENTATION_FAULT)
else
if (CanAccess(PTE.ProtectBits) == False)
RaiseException(PROTECTION_FAULT)
else if (PTE.Present == True)
TLB_Insert(VPN, PTE.PFN, PTE.ProtectBits)
RetryInstruction()
else if (PTE.Present == False)
RaiseException(PAGE_FAULT)
| valid | present | outcome | |
|---|---|---|---|
| case 1 | 0 | (moot) | RaiseException(SEGMENTATION_FAULT) |
| case 2 | 1 | 1 | TLB_Insert, retry β hit |
| case 3 | 1 | 0 | RaiseException(PAGE_FAULT) |
And the OS side β the handler itself, seven lines that carry the whole illusion (Figure 21.3):
PFN = FindFreePhysicalPage()
if (PFN == -1) // no free page found
PFN = EvictPage() // run replacement algorithm
DiskRead(PTE.DiskAddr, PFN) // sleep (waiting for I/O)
PTE.present = True // update page table with present
PTE.PFN = PFN // bit and translation (PFN)
RetryInstruction() // retry instruction
21.6 When Replacements Really Occur
Waiting until memory is entirely full before evicting is a little unrealistic. Real systems keep a cushion, governed by high and low watermarks watermarks The high/low free-memory thresholds (HW/LW) governing proactive eviction: below LW the swap daemon wakes and frees pages until HW are available, so the fault path rarely has to evict synchronously. defined in ch. 21 β open in glossary and patrolled by a background thread β the swap daemon swap daemon The background thread (a.k.a. page daemon; 'daemon' via Multics from Maxwell's demon) that evicts pages when free memory dips below the low watermark, until the high watermark is restored β enabling clustered swap writes along the way. defined in ch. 21 β open in glossary :
1Plenty free β the daemon sleeps
Free pages sit comfortably above the low watermark. Page faults are cheap-ish: the handler grabs a free frame directly, no eviction in sight. The background thread naps.
Aside: Daemon
Usually pronounced βdemonβ: an old term for a background thread or process that does something useful. The source (once again!) is Multics β CorbatΓ³βs team borrowed it from Maxwellβs demon of thermodynamics, βan imaginary agent which helped sort molecules of different speeds and worked tirelessly in the background.βTip: Do Work In The Background
Batching work in the background pays repeatedly: disks schedule grouped writes better; applications see writes βcompleteβ instantly; some work evaporates entirely (write a file, delete it β the disk never hears about it); and idle time gets used. File-write buffering and the swap daemon are the same idea wearing different hats.21.7 Summary
More memory than physically exists: a present bit in the PTE, a page-fault handler that fetches from swap, and a policy (pending) for making room. The amazing part is that it all happens transparently β the process just accesses its private, contiguous virtual memory, never learning that its pages scatter across arbitrary frames or vanish to disk entirely. In the common case, a memory access is fast; in the worst case, one instruction takes multiple disk operations and many milliseconds β the hierarchyβs whole span, hidden inside a single load.
Homework (Measurement): vmstat + mem.c
Watch swapping happen: run vmstat 1 beside mem.c and track swpd/free as allocations grow; push past your RAM (mem 5000, 6000β¦) and watch si/so light up; measure the bandwidth cliff between fits-in-memory and constantly-swapping runs (make the graph!); find where allocation fails as swap itself (swapon -s) runs out. Get it at ostep-homework.Check yourself
1.On a TLB miss, the hardware inspects the PTE. Name the three cases and their outcomes (Figure 21.2).
2.Reconstruct the page-fault handler's algorithm (Figure 21.3), in order.
3.Why don't operating systems wait until memory is completely full before evicting β and what governs the proactive approach?
4.The swap daemon evicts many pages at once. What extra performance trick does batching unlock?
5.The book warns that a bad page-replacement decision can make a program run 10,000β100,000Γ slower. Where does that terrifying ratio come from?