DSA, Database System & Operating System β Memory Management, File Systems & Administration, NEC licence examination syllabus (Nepal Engineering Council).
Demand Paging and Performance
Loading pages only when touched β measured, along with the arithmetic that shows why the fault rate must be tiny.
π Where this lives: demand paging is why a 500 MB application starts in under a second. Only the pages actually executed are loaded, and a typical startup touches a small fraction of the binary. It is also why the second launch of an app is faster β the pages are still in the page cache. And it is the mechanism behind mmap: mapping a 10 GB file costs nothing until you read from it, which is how databases and search indexes handle files larger than RAM. Search "lazy loading demand paging startup time".
One fault per thousand accesses sounds negligible. Watch the slowdown: because servicing a fault takes milliseconds against nanoseconds for memory, that one-in-a-thousand dominates everything else. This is why thrashing collapses a system rather than degrading it.
DEMAND PAGING: bring a page into memory only when it is
REFERENCED, never in advance.
Β· a page-table entry has a VALID/INVALID bit
Β· valid β the page is in memory, translate normally
Β· invalid β either the address is illegal, OR the page is on
disk and not yet loaded
The MMU cannot tell those two cases apart, so it traps to the
OS, which consults its own records.
THE PAGE-FAULT SEQUENCE β six steps, and it is examined:
1. the MMU finds valid = 0 β TRAP to the OS
2. the OS checks: is this a legal address for this process?
NO β SIGSEGV, terminate the process
YES β continue
3. find a FREE FRAME (or evict one β see page replacement)
4. schedule a disk read of the page into that frame
5. update the page table: frame number, valid = 1
6. RESTART the faulting instruction
Step 6 is subtle: the instruction is re-executed from the
beginning, not resumed. That requires the CPU to be able to
restart any instruction cleanly, which constrains instruction
set design β a block-move instruction that has already copied
half its bytes must be restartable or the fault is
unrecoverable.
MINOR vs MAJOR FAULTS β the distinction that matters in
practice:
MINOR (soft) fault the page is in memory already but not
mapped in THIS page table β a shared
library another process loaded, or a
zero-fill-on-demand page. No disk I/O.
Cost: microseconds.
MAJOR (hard) fault the page must be read from disk.
Cost: milliseconds on a spinning disk,
~100 Β΅s on SSD.
A high MINOR fault count is normal. A high MAJOR fault count
means thrashing.
Measured β demand paging in action
pf.c
/* Verified on Darwin arm64, 16 KB pages. Allocate 64 MB, then
touch one byte in every page and count the faults. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
#include <time.h>
static void faults(const char *tag) {
struct rusage r; getrusage(RUSAGE_SELF, &r);
printf(" %-28s minor=%-8ld major=%ld\n",
tag, r.ru_minflt, r.ru_majflt);
}
#define MB 64
int main(void) {
long n = (long)MB*1024*1024;
faults("at start");
volatile char *p = malloc(n); /* ALLOCATE only */
faults("after malloc (untouched)");
for (long i = 0; i < n; i += getpagesize()) p[i] = 1;
faults("after touching every page");
for (long i = 0; i < n; i += getpagesize()) p[i] = 2;
faults("after SECOND pass");
return 0;
}
MEASURED OUTPUT:
at start minor=284 major=1
after malloc (untouched) minor=286 major=1
after touching every page minor=4382 major=1
first touch of 64 MB: 8.7 ms
after SECOND pass minor=4382 major=1
second pass: 5.2 ms
pages in 64 MB at 16KB = 4096
THREE THINGS THAT OUTPUT PROVES, exactly as the theory
predicts:
1. malloc ALLOCATED NOTHING PHYSICAL.
284 β 286 faults for a 64 MB allocation: just two, for the
allocator's own bookkeeping. The 64 MB exists as ADDRESS
SPACE with no frames behind it. This is why a program can
malloc more than it will ever use, and why
"allocation succeeded" does not mean "memory is available".
2. EXACTLY ONE FAULT PER PAGE ON FIRST TOUCH.
4382 β 286 = 4,096 faults
64 MB / 16 KB = 4,096 pages
A perfect match. Every page was faulted in on demand,
one at a time, precisely when first written.
3. ZERO FAULTS ON THE SECOND PASS.
4382 β 4382. The pages are resident, so translation
succeeds in hardware with no OS involvement at all. Time
fell from 8.7 ms to 5.2 ms β the residual difference is the
memory writes themselves plus TLB misses.
That 8.7 β 5.2 ms gap IS the cost of 4,096 minor faults:
(8.7 β 5.2) ms / 4096 β 0.85 Β΅s per fault
Sub-microsecond, because these are MINOR faults β the OS
only had to allocate a zeroed frame, with no disk I/O.
A MAJOR fault on an SSD would be ~100 Β΅s, over 100Γ more.
That ratio is why the fault-rate arithmetic below is so
unforgiving.
WHY major=1 THROUGHOUT: exactly one hard fault, during program
startup (loading the binary). Everything afterwards was served
from memory. On a warm system, major faults are rare β which
is the healthy state.
Effective access time β why the fault rate must be tiny
EAT = (1 β p) Γ memory_access + p Γ page_fault_time
where p is the page-fault RATE (probability a given access
faults).
WORKED EXAMPLE β the classic figures:
memory access = 200 ns
page fault time = 8 ms = 8,000,000 ns
EAT = (1 β p)(200) + p(8,000,000)
= 200 β 200p + 8,000,000p
= 200 + 7,999,800p
p = 0 β 200 ns (no slowdown)
p = 0.001 β 8,200 ns 41Γ SLOWER
p = 0.0001 β 1,000 ns 5Γ slower
p = 0.00001 β 280 ns 1.4Γ slower
ONE FAULT PER 1,000 ACCESSES MAKES THE SYSTEM 41Γ SLOWER.
FOR LESS THAN 10% DEGRADATION:
220 > 200 + 7,999,800p
20 > 7,999,800p
p < 0.0000025 = 1 fault per 400,000 accesses
That is the number to remember: to keep paging overhead under
10%, fewer than one access in 400,000 may fault. Virtual
memory works only because locality of reference makes real
fault rates far below that.
REDO WITH AN SSD (100 Β΅s = 100,000 ns):
EAT = 200 + 99,800p
p = 0.001 β 299.8 ns, only 1.5Γ slower
An SSD makes paging roughly 80Γ more forgiving. That single
change is why swap became usable again after two decades of
"never enable swap" advice β the advice was correct for
spinning disks and is wrong for SSDs.
COPY-ON-WRITE β demand paging applied to fork():
Β· after fork(), parent and child SHARE all pages, marked
read-only
Β· the first WRITE by either causes a protection fault
Β· the OS copies just that page and marks both writable
β fork() copies only the page TABLE, not the data
This is why fork was measured at 356 Β΅s (in the threads
topic) rather than seconds: a 1 GB process forks without
copying 1 GB. And exec() immediately afterwards discards the
address space entirely, so in the common fork+exec case
almost nothing is ever copied.
PAGE PREFETCHING / PREPAGING: bring in several adjacent pages
on a fault, betting on spatial locality.
β fewer faults if the guess is right
β wasted I/O and wasted frames if wrong
Modern kernels do READAHEAD for sequential file access
(detected by pattern), which is the same idea applied to the
page cache.
The p < 0.0000025 result is the single most important number in virtual memory. Paging is not "a bit slower than RAM" β a fault is roughly 40,000Γ a memory access on a spinning disk, so the entire scheme depends on faults being astronomically rare. Locality of reference is not a nice property; it is the load-bearing assumption.
π Go further: the SSD calculation above has quietly reversed twenty years of received wisdom. The old advice β "disable swap, buy more RAM" β was correct when a fault cost 8 ms; at 100 Β΅s, a small amount of swap is a useful safety valve rather than a performance cliff. Kubernetes disabled swap entirely for years and only recently added support back, for exactly this reason. Meanwhile zswap and macOS's compressed memory take it further: compress the page in RAM (a few Β΅s) instead of writing it out at all. Search "Kubernetes swap support beta" and "zswap vs zram".
π‘ Exam angle: list the six page-fault steps, ending with restart the instruction. The EAT calculation is a near-certain numerical: given memory access time, fault service time and fault rate, compute EAT and the slowdown β and be ready to solve for the p that keeps degradation under a stated bound. Distinguish minor from major faults. Explain copy-on-write as demand paging applied to fork, and state that fork copies the page table rather than the data.
Syllabus points
Page faults
Effective access time (numerical)
Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.
Related topics in Memory Management, File Systems & Administration