Introduction

Virtual memory separates the logical memory a program sees from the physical memory it occupies, so that a process need not be entirely in memory to run. Programs often contain error-handling code that rarely runs, arrays declared larger than they are used, and features few users touch. Loading only what is referenced lets a program be larger than physical memory, lets more processes share memory, and makes process start-up faster.

The usual implementation is demand paging: Paging, Page Tables and TLB, bringing a page into use when it is first referenced. A reference to a legal page that is not currently mapped/present causes a page fault. A major, disk-backed fault reads backing storage; a soft fault may instead map an already resident frame, and demand-zero allocation supplies a zero-filled page without a backing-storage read. Disk-backed faults are very expensive compared with memory accesses, so keeping their rate tiny matters; excessive paging activity can cause thrashing.

The valid-invalid bit, the page-fault service sequence, effective access time with faults, copy-on-write, frame allocation, the locality and working-set models, and thrashing are the standard facts. Choosing which page to evict is in Page Replacement Algorithms.

Prerequisites

Core concepts

Demand paging and the valid-invalid bit

Each page-table entry has a valid-invalid bit. In this simplified present-mapping model, valid means a legal page is present in this mapping. Invalid means either an illegal address or a legal page whose mapping is absent: it may require a disk read, a mapping to an already resident frame, or demand-zero allocation. A reference to an invalid entry traps to the OS, which looks at its own records (usually in the PCB) to tell the two cases apart.

  • Pure demand paging starts a process with no pages in memory; every first reference to a page faults. A process that touches 7 distinct pages with enough frames for all of them takes exactly 7 page faults.
  • Prepaging loads some pages ahead of demand, for example the working set of a process being resumed, gambling that they will be used.
  • The locality of reference of real programs (a loop runs over a few pages for a while, then moves on) is what makes demand paging work.

Terminology

TermMeaning
Page faultReference to a page whose entry is invalid
Major (hard) faultThe page must be read from secondary storage
Minor (soft) faultNo backing-storage read is needed: for example, map an already resident frame or supply a zero-filled page
Backing store, swap spaceThe secondary-storage area that holds pages not in memory
Free-frame listFrames available for incoming pages, often zero-filled on demand
Dirty (modify) bitSet on a write; a clean victim need not be written back

How a page fault is serviced

Flowchart of servicing a page fault: the valid-bit check, the trap, the legality check, finding a free frame or evicting a victim, the disk read while another process runs, the page-table update and the restart of the instruction.
Figure 1. Major, disk-backed page-fault service: the trap, the legality check, finding a frame (evicting and writing back a dirty victim if necessary), the disk read during which another process runs, the page-table update and the restart of the faulting instruction.

Restarting the instruction. The hardware must be able to restart any instruction after a fault, as if it had never started. This is hard for an instruction that modifies memory and can fault part-way, such as a block move whose source and destination overlap, or an instruction with auto-increment addressing. Hardware either checks both ends of the operands before starting, or saves enough state to undo the partial effect (Tanenbaum 3.6.3 calls this instruction backup).

Minimum number of frames. The architecture fixes a minimum: every page that one instruction can touch must be in memory at once. A memory-to-memory move instruction whose own bytes, source operand and destination operand can each straddle a page boundary can touch 6 pages, so such a machine needs at least 6 frames per process.

Mathematical explanation

Effective access time with page faults

For this disk-backed-fault cost model, let mm be the memory access time, SS the fault service time and pp the disk-backed-fault rate (faults per memory reference). Then

EAT=(1−p) m+p S.\text{EAT} = (1 - p)\,m + p\,S .

SS is dominated by the disk read (and a write-back for a dirty victim): milliseconds, against nanoseconds for mm, so even a tiny pp matters.

Example 1. m=100m = 100 ns, S=5S = 5 ms =5,000,000= 5{,}000{,}000 ns, p=0.001p = 0.001:

EAT=0.999×100+0.001×5,000,000=99.9+5000=5099.9 ns,\text{EAT} = 0.999 \times 100 + 0.001 \times 5{,}000{,}000 = 99.9 + 5000 = 5099.9 \text{ ns},

about 51 times slower than with no faults. To keep the slowdown within 10% (EAT at most 110 ns) we need 100+p×4,999,900≤110100 + p \times 4{,}999{,}900 \le 110, that is p≤1/499,990p \le 1/499{,}990: fewer than one fault in about half a million references.

Example 2, dirty victims. m=120m = 120 ns; servicing a fault takes 6 ms when the victim is clean and 15 ms when it is dirty and must be written back first; 40% of victims are dirty. The mean service time is 0.6×6+0.4×15=9.60.6 \times 6 + 0.4 \times 15 = 9.6 ms =9,600,000= 9{,}600{,}000 ns. For EAT at most 240 ns:

(1−p)×120+p×9,600,000≤240  ⟺  p×9,599,880≤120  ⟺  p≤179,999.(1 - p) \times 120 + p \times 9{,}600{,}000 \le 240 \iff p \times 9{,}599{,}880 \le 120 \iff p \le \frac{1}{79{,}999}.

Convention. Some questions write EAT=m+pS\text{EAT} = m + pS, counting the memory access even on a fault (the restarted instruction does access memory). The difference is p mp\,m, negligible unless pp is large; use the form the question gives.

TLB and page faults together

Combine the TLB from Paging, Page Tables and TLB with faults. Let the TLB lookup take t=10t = 10 ns, memory m=100m = 100 ns, the TLB hit ratio be 0.9, and suppose that 1% of the references that miss the TLB also fault, with S=2S = 2 ms. State the model: a TLB miss costs t+mt + m for the page-table read; if the page is present, one more mm for the data; if it faults, SS and then a restarted reference that hits the now-updated TLB, t+mt + m.

EAT=0.9×110+0.1×[0.99×210+0.01×(110+2,000,000+110)]=2120.01 ns.\text{EAT} = 0.9 \times 110 + 0.1 \times \bigl[0.99 \times 210 + 0.01 \times (110 + 2{,}000{,}000 + 110)\bigr] = 2120.01 \text{ ns}.

The fault term contributes 2,000.22 of those nanoseconds, although only 0.1% of references fault.

A two-level walk, faults and dirty victims together

Memory access m=100m = 100 ns, TLB time negligible, a two-level page table, TLB hit ratio 0.95. Of the references that miss the TLB, 0.1% fault; a fault takes 5 ms with a clean victim and 10 ms with a dirty one, and 30% of victims are dirty. After a fault the instruction restarts and hits the TLB.

  • TLB hit: m=100m = 100 ns.
  • TLB miss, page present: two table reads and the data, 3m=3003m = 300 ns.
  • TLB miss, fault: two table reads, the service time and the restarted access, 2m+S+m2m + S + m, with mean S=0.7×5+0.3×10=6.5S = 0.7 \times 5 + 0.3 \times 10 = 6.5 ms.
EAT=0.95×100+0.05×[0.999×300+0.001×(200+6,500,000+100)]=95+0.05×6800=435 ns.\text{EAT} = 0.95 \times 100 + 0.05 \times \bigl[0.999 \times 300 + 0.001 \times (200 + 6{,}500{,}000 + 100)\bigr] = 95 + 0.05 \times 6800 = 435 \text{ ns}.

Counting a population of 2,000,000 references path by path (1,900,000 hits, 99,900 present misses, 70 clean and 30 dirty faults) gives the same 435 ns. Without any faults the EAT would be 95+0.05×300=11095 + 0.05 \times 300 = 110 ns, so 100 faults in 2,000,000 references make it almost four times larger.

Loop order and page faults

int A[128][128] with 4-byte integers, stored row by row, and 512-byte pages, with the array beginning on a 512-byte page boundary, so each row (128×4=512128 \times 4 = 512 bytes) fills exactly one page. The process has one frame for the array, and the array is not in memory at the start.

  • Row by row (for i: for j: A[i][j] = 0): the 128 elements of a page are used together, so there is one fault per row: 128 faults.
  • Column by column (for j: for i: A[i][j] = 0): consecutive references are in different rows, hence different pages, so every one of the 128×128=16,384128 \times 128 = 16{,}384 references faults.

With cold start, no other references/replacement interference, and FIFO or LRU, 2 frames leave the counts unchanged, and 128 frames (the whole array) are required for the column order to drop to 128 faults. These threshold claims are not policy-independent; OPT can obtain hits with fewer frames. Under the stated FIFO/LRU assumptions, loop order drives the difference.

Frame allocation

With FF free frames and processes of sizes sis_i (in pages), equal allocation gives each of nn processes ⌊F/n⌋\lfloor F/n \rfloor frames, and proportional allocation gives process ii

ai=⌊si∑jsj F⌋.a_i = \left\lfloor \frac{s_i}{\sum_j s_j} \, F \right\rfloor .

With F=64F = 64 and sizes 25, 75 and 200 pages, proportional allocation gives 5, 16 and 42 frames (from 5.33, 16 and 42.67); the floors leave 1 frame in the free pool. Equal allocation gives 21 each, also leaving 1. Priority can be mixed in by weighting the sizes.

Global versus local replacement. With global replacement a faulting process may take a frame from any process; throughput is usually better, but a process's fault rate depends on the others. With local replacement it replaces only its own pages, so its behaviour is predictable but memory may sit idle in other processes.

Copy-on-write

In the simple counting model, parent and child retain their shared private writable COW mappings until the first write, with neither unmapping/exiting first; explicitly shared mappings are excluded. After fork(), eligible private writable pages are shared and temporarily write-protected for copy-on-write. The first write by either process to a shared page traps; the OS copies that page into a free frame, maps the copy writable for the writer, and lets the write proceed. Pages never written are never copied, so a child that immediately calls exec() costs almost nothing. If the child writes to 3 distinct pages (several times each) and the parent writes to none, exactly 3 pages are copied. See Process Creation and fork() for the process side.

Thrashing and the working-set model

A process that does not have enough frames for the pages it is actively using faults, evicts a page it will need almost at once, and faults again. It spends more time paging than executing: it thrashes. With global replacement, thrashing spreads: faulting processes steal frames from others, CPU utilisation falls, a naive scheduler admits more processes to raise utilisation, and the fault rate rises further.

CPU utilisation against degree of multiprogramming
Figure 2. CPU utilisation rises with the degree of multiprogramming until the combined working sets no longer fit in memory; beyond that point page faults dominate and utilisation collapses, which is thrashing.

The working set

The working set W(t,Δ)W(t, \Delta) is the set of distinct pages referenced in the last Δ\Delta references up to time tt (the working-set window). Its size is WSS\text{WSS}. If the total demand D=∑iWSSiD = \sum_i \text{WSS}_i exceeds the number of frames mm, some process lacks its working set and the system will thrash; the OS should then suspend a process (swap it out) rather than admit another.

Example. Reference string 1 2 1 3 2 1 4 4 5 4 5 6 5 4 6 6 (times 1 to 16), Δ=4\Delta = 4:

Time ttLast 4 referencesW(t,4)W(t, 4)WSS
61 3 2 1{1, 2, 3}3
73 2 1 4{1, 2, 3, 4}4
104 4 5 4{4, 5}2
165 4 6 6{4, 5, 6}3

The program moves from a locality {1, 2, 3} to a locality {4, 5, 6}; the working set is largest (4 pages) at the transition. A Δ\Delta that is too small misses parts of a locality; one that is too large spans several localities.

Admission. Four processes with working-set sizes 30, 45, 60 and 25 need D=160D = 160 frames; with 150 frames the system is over-committed and one process should be suspended.

Page-fault frequency

A simpler control measures each process's fault rate directly: above an upper bound the process gets more frames, below a lower bound it loses some. If no frames are free when a process needs more, a process is suspended.

Important properties and observations

  • A page fault traps to the OS. In the major, disk-backed path the process blocks during the disk read and the CPU can run another process; soft/resident-frame and demand-zero faults need no backing-storage read.
  • In the disk-backed-fault cost model, the fault rate must be very small (around one in hundreds of thousands of references) for paging to be acceptable.
  • A dirty victim roughly doubles the service time because of the write-back.
  • Thrashing is a lack of frames for the working sets, not a scheduling problem; adding processes makes it worse.
  • Copy-on-write makes fork() cheap and copies only pages that are written.

Common misconceptions.

  • "Every invalid entry is an error." An invalid entry may be a legal page that is on disk.
  • "More multiprogramming always raises utilisation." Only until the working sets exceed memory.
  • "Local replacement prevents thrashing." It confines thrashing to the process that lacks frames, which still runs slowly and also slows the paging device for everyone.

GATE examination perspective

  • EAT with faults. Convert milliseconds to nanoseconds, include the write-back fraction for dirty victims, and solve the inequality for the largest fault rate.
  • Combined TLB, page table and fault. Write the model (which accesses happen on each path) before writing numbers.
  • Working-set tables. Count distinct pages in the window ending at tt, including tt itself.
  • Thrashing causes and cures. Cause: total working sets exceed frames. Cure: suspend processes, working-set or fault-frequency control.
  • Pure demand paging. Faults at least the number of distinct pages referenced.
  • Copy-on-write counts. In the simple retained-private-COW model above (neither unmaps/exits first), count one copy per distinct original shared COW page written by either process; this excludes explicitly shared mappings.

Summary

Sources

  1. A. Silberschatz, P. B. Galvin, G. Gagne, Operating System Concepts, 10th ed., Wiley: Chapter 10 (10.1 Background, 10.2 Demand Paging, 10.3 Copy-on-Write, 10.5 Allocation of Frames, 10.6 Thrashing).
  2. A. S. Tanenbaum, H. Bos, Modern Operating Systems, 4th ed., Pearson: Chapter 3 (3.3 Virtual Memory, 3.4.8 The Working Set Page Replacement Algorithm, 3.5.1 Local versus Global Allocation Policies, 3.5.2 Load Control, 3.6.2 Page Fault Handling, 3.6.3 Instruction Backup).

Next steps