Demand paging and fault handling
Follow a valid access through lazy allocation, distinguish minor and major faults, and measure first-touch cost separately from steady state.
On this page
The question for today
What you’ll understand
- Distinguish an allowed virtual range from an installed resident mapping.
- Classify minor and major faults without treating either as a programming error.
- Calculate fault-service overhead using explicit measured or assumed costs.
An application may obtain a large virtual mapping before physical pages have been supplied for all of it. Demand paging postpones work until an access requires backing or permissions to change. The resulting fault can be expected behavior. The engineering question is which work the fault performs, which thread waits for it, and whether that work appears during startup or a latency-sensitive request.
A valid range can still fault on first access
The operating system records which address ranges a process may access and under what conditions. That range-level policy is distinct from the presence of every hardware page-table entry. On a first anonymous write, the kernel may need to allocate a frame, supply zeroed memory, install a writable mapping, and resume the instruction. A first read can sometimes use an existing shared zero page instead. Details depend on architecture, mapping type, page size, and kernel policy; do not assume that reading one byte proves an entire allocation has private physical backing.
The instruction that caused a recoverable fault is retried after the mapping is repaired. A fault on an invalid range or a genuinely forbidden access cannot be repaired merely by finding more free RAM. The kernel instead delivers the appropriate signal or otherwise handles the error. Mapping operations themselves can fail earlier, so robust software checks their return values as well as planning for runtime memory pressure. Lazy allocation changes the time at which resources are needed; it does not remove the resource requirement.
Classify the work rather than the drama
Linux resource counters distinguish minor faults, resolved without the page-loading I/O counted as a major fault, from major faults requiring that I/O. Mapping a file whose contents are already in the page cache can fault without a fresh storage read. Demand-zero allocation and ordinary copy-on-write commonly appear as minor faults. A minor fault still consumes kernel execution and may encounter allocation contention; its name is not a latency guarantee. A major fault is also not proof that a particular application read call issued exactly one disk operation.
Measure differences in counters around the workload phase of interest. A cumulative fault count includes initialization that may be irrelevant to a steady-state regression. Align the count with wall time, system CPU time, memory pressure, and storage activity. Shared page-cache state can make repeated runs faster, while background workloads may change that state again. Document whether the benchmark intends a warm-cache or cold-start comparison and avoid dropping host caches indiscriminately on a machine serving unrelated work. A reproducible experiment controls what it can and records what it cannot.
Move predictable work out of a critical path
A service may initialize a bounded pool and deliberately touch pages before accepting traffic. That can make initial mapping and allocation work visible during readiness checks. It does not guarantee future residency: reclaim, copy-on-write, mapping changes, and growth can introduce faults later. Locking memory has separate limits and consequences and is not a universal optimization. Start with the latency requirement and an explicit memory budget; a blanket prefault of every reserved byte can transform a cheap address reservation into an avoidable physical-memory crisis.
In the queue lab, interpret arrivals as normalized fault-service requests and service as simplified capacity. Press Reset, explicitly set arrival two and service three, predict the initial four-job backlog drains after four model seconds, then Play or Step. For a separate comparison, Reset again, set both arrival four and service three, predict one-job-per-second growth from four, then Play or Step. These are separate runs, not a live rate switch: parameter edits retain elapsed time and recompute the initial-value model. The graph does not represent Linux fault queues, page-cache readahead, or thread scheduling. Its separate M/M/1 mean needs Poisson arrivals, exponential service times, one server, and stability; an average cannot guarantee a deadline.
Work it through
First-touch cost of a fresh buffer
A fresh page-aligned 64 MiB anonymous buffer is written once per 4 KiB page. Assume no huge pages and one serial minor fault costing an illustrative two microseconds per page.
Convert the allocation into base pages: 64 × 1,048,576 / 4,096 = 16,384 pages. This counts first touched pages, not every byte write.
Multiply 16,384 by two microseconds to obtain 32,768 microseconds, or 32.768 milliseconds of modeled first-touch fault service.
Compare a second pass after residency is established. Under the stated assumptions it avoids those first-touch faults, but ordinary stores, cache misses, scheduling, and later reclaim still affect elapsed time.
A modest per-page cost can create a visible startup burst. Measure the actual platform rather than treating two microseconds as a portable constant.
The living notebook
Explore the model
Interactive lab · queue
Fault arrival and service pressure
Press Reset, explicitly set both λ=2 and μ=3, predict the initial four-job backlog drains at t=4, then Play or Step. For a separate comparison, Reset, set both λ=4 and μ=3, predict growth from four, then Play or Step. Parameter edits alone retain elapsed time. This fluid model is not a kernel fault handler; the M/M/1 mean has separate stochastic assumptions.
- Fluid backlog
- 4
- Net rate · λ − μ
- −1 /s
- M/M/1 mean residence
- 1 s
Fluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forMoving first-touch work changes when demand arrives; it does not make fault-service capacity unlimited.
Pause & reason
Check your understanding
Your turn
Try it yourself
One million serial modeled accesses have fault probability 0.001. Nonfaulting service is 100 ns and faulting service is 10 μs. Estimate the mean service time per access.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Use the two-case weighted mean; convert microseconds to nanoseconds.
Compare with the solution
The mean is 0.999 × 100 ns + 0.001 × 10,000 ns = 109.9 ns per modeled access. That is 109.9 ms for one million nonoverlapped accesses under this simplified model. It does not specify the latency distribution or guarantee how real clustered faults overlap.
Keep the idea
Take it with you
- A valid address range need not have every physical page installed yet.
- Minor and major fault counters classify work, not correctness or a fixed latency.
- Separate startup first-touch costs from steady-state measurements.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.