What is a page fault

What is a page fault

The term “page fault” sounds alarming — like something has gone badly wrong. In reality, page faults are one of the most routine, constantly-occurring events in any modern operating system, happening thousands of times per second on an active machine, almost entirely invisibly. Understanding what a page fault actually is — and the important distinction between the normal, healthy kind and the genuinely erroneous kind — is fundamental to understanding how virtual memory works at all.

Defining a Page Fault

A page fault is a hardware exception (trap) raised by the CPU’s Memory Management Unit (MMU) when a running program attempts to access a virtual memory page that is not currently mapped to a valid, present physical frame — as recorded by that page’s “Present” bit in the page table being 0, or by other conditions like a protection violation.

When this trap fires, execution of the running program is suspended, and control transfers to the operating system’s page fault handler, which determines what to do next: load the needed page from disk (a legitimate, expected case), or terminate the offending process (a genuine error, like a null pointer dereference).

The Anatomy of a Page Fault

1. CPU executes an instruction referencing virtual address V
2. MMU translates V using the page table
3. MMU discovers: Present bit = 0 (or a protection violation)
4. MMU raises a page fault exception (trap)
5. CPU saves the current execution context, jumps to the
   OS's page fault handler (interrupt/trap vector)
6. OS page fault handler examines:
      - the faulting virtual address
      - the reason for the fault (not present? protection violation? write to read-only?)
      - whether this address falls within a valid region of
        the process's address space
7. Based on that analysis, OS either:
      (a) Services the fault (loads the page, adjusts the stack,
          copies a COW page, etc.) and resumes the process, OR
      (b) Delivers a signal / raises an exception to terminate
          or notify the process (e.g., SIGSEGV on Linux, an
          Access Violation exception on Windows)

Types of Page Faults

Page faults are broadly categorized based on cost (how expensive they are to resolve) and validity (whether the access was actually legitimate).

Minor (Soft) Page Faults

A minor fault occurs when the referenced page is not currently mapped into the process’s page table, but the actual page content is already available somewhere in physical memory — for example:

  • The page was previously loaded and is sitting in the OS’s page cache (e.g., a shared library already loaded by another process).
  • The page is part of a copy-on-write mapping, and the underlying physical frame already exists (shared with the parent/sibling process).
  • The page is a freshly-requested zero-filled page (e.g., newly-grown heap or stack memory), which the OS can satisfy instantly without any disk I/O.

Minor faults are resolved extremely quickly — no disk I/O is required, just updating page table entries — and are a completely normal, expected part of everyday process execution.

Major (Hard) Page Faults

A major fault occurs when the required page genuinely isn’t anywhere in physical memory and must be read from disk — either from the executable/library file itself (first-time demand paging) or from swap space (a page that was previously evicted to make room for something else). Major faults are dramatically more expensive, since they involve actual storage I/O — potentially milliseconds, compared to the nanosecond-to-microsecond cost of a minor fault.

A high rate of major faults is a strong warning sign of memory pressure and a potential precursor to thrashing.

Invalid Page Faults

An invalid fault occurs when the memory access itself was never legitimate in the first place — accessing an address entirely outside any region the process has ever been granted (e.g., a wild/null pointer dereference), or violating protection rules (e.g., attempting to write to a read-only code segment). These faults are not “serviced” by loading a page — instead, the OS delivers an error to the process, typically resulting in termination:

  • Linux/UNIX: SIGSEGV (segmentation violation) for invalid memory access, SIGBUS for certain alignment/mapping errors
  • Windows: an EXCEPTION_ACCESS_VIOLATION structured exception

Page Faults vs. “Errors”: An Important Distinction

It’s worth emphasizing clearly: the overwhelming majority of page faults that occur on a running system are completely normal and expected — minor faults from demand paging and copy-on-write happen constantly and are essential to how virtual memory achieves its efficiency. Only a small subset — invalid faults — represent actual bugs or genuine errors in program behavior. Describing a page fault generically as “an error” is a common misconception; it’s more accurate to describe it as an exception requiring OS intervention, which is very often entirely routine.

Page Fault Handling in Detail: What the OS Actually Does

When a legitimate (non-invalid) page fault occurs, the OS’s fault handler typically performs these steps:

  1. Identify the faulting address and the Virtual Memory Area (VMA) it belongs to (Linux terminology) — essentially, which logical mapping (heap, stack, memory-mapped file, shared library, etc.) does this address fall under.
  2. Check permissions — was this a read, write, or execute attempt, and is it allowed for this VMA?
  3. Locate or allocate a free physical frame — if physical memory is full, invoke a page replacement algorithm (LRU, Clock/Second-Chance, etc.) to select a victim page to evict first.
  4. If evicting a dirty page, write its contents back to disk/swap before reusing the frame.
  5. Load the required content into the frame — from the executable file, a memory-mapped file, or swap space — or simply zero-fill it for new stack/heap growth.
  6. Update the page table entry, setting the Present bit and Frame Number.
  7. Update the TLB (either automatically by hardware on the next access, or explicitly depending on architecture).
  8. Restart the faulting instruction.

Real-World Frequency: Page Faults Are Everywhere

On any modern desktop or server OS, you can directly observe live page fault activity:

  • Linux: ps -o min_flt,maj_flt -p <pid> or reading /proc/[pid]/stat shows cumulative minor and major fault counts for a process. System-wide, sar -B reports faults per second across the whole machine.
  • Windows: Task Manager’s “Details” tab can show a “Page Faults” column per process; Resource Monitor and Performance Monitor expose “Page Faults/sec” and separately “Hard Faults/sec” system-wide.
  • macOS/iOS: Activity Monitor and Instruments both expose page-in/page-out statistics per process.

It’s completely normal to see minor fault counts in the tens of thousands for an actively-used application, while major fault counts should generally remain low on a healthy, non-memory-constrained system.

Page Faults Across Platforms

Linux/UNIX

The Linux kernel’s handle_mm_fault() function is the central page fault handling routine, dispatching to different logic depending on whether the fault is on an anonymous mapping (heap/stack), a file-backed mapping (mmap‘d files, shared libraries), or a copy-on-write page. Linux’s dmesg and kernel oops logs will show detailed fault information (including the faulting instruction pointer and register state) when a kernel-level fault occurs — critical for kernel debugging.

Windows

Windows’ Memory Manager similarly distinguishes soft faults (analogous to Linux minor faults) from hard faults (analogous to major faults), and its Structured Exception Handling (SEH) mechanism is what surfaces invalid access violations to applications, which debuggers like WinDbg can catch and analyze via crash dump files.

Android and iOS

Both, being built on Linux (Android) and a UNIX-derived XNU kernel (iOS), inherit fundamentally the same page fault mechanics. Android’s ART runtime and Zygote process-forking model rely heavily on minor faults and copy-on-write semantics for fast app startup, since new app processes are forked from an already-warmed-up Zygote process template.

Real-World Use Cases That Rely on Page Faults

  • Lazy loading of executables and shared libraries (demand paging) — discussed extensively in our companion article on demand paging.
  • Stack growth: most OSes implement automatic stack growth by catching a page fault just below the current stack pointer and, if it falls within a permitted “guard region,” transparently allocating a new stack page rather than terminating the process.
  • Guard pages for security and debugging: deliberately unmapped “guard pages” placed around buffers or stack regions cause an immediate, detectable page fault (crash) if a buffer overflow or stack overflow tries to write past its boundary — a common exploit-mitigation and debugging technique.
  • Memory-mapped I/O and databases: systems like SQLite and various key-value stores memory-map database files directly, relying on page faults to lazily bring in exactly the data pages actually queried.

Troubleshooting High Page Fault Rates

  1. Distinguish minor vs. major faults first — a high minor fault rate is often benign (normal COW/demand-paging activity); a high major fault rate indicates real memory pressure or disk I/O bottlenecks.
  2. Correlate with available free memory — check if free RAM is critically low when major faults spike; this points toward insufficient physical memory for the current workload.
  3. Check for swapping activity — on Linux, vmstat 1‘s si/so columns; sustained non-zero values alongside major faults strongly suggest a system under real memory pressure, potentially approaching thrashing.
  4. Profile the specific application — tools like perf record (Linux) with fault-related events, or Windows Performance Analyzer, can pinpoint exactly which code paths or data structures are generating excessive faults.
  5. Consider prefetching or prepaging for predictable large sequential access patterns to reduce the fault-driven latency spikes.

Best Practices

  1. Don’t panic at raw page fault counts in monitoring dashboards — always separate minor from major fault metrics before drawing conclusions.
  2. Use guard pages deliberately in security-sensitive or debugging builds to catch buffer/stack overflows immediately via a controlled page fault rather than silent memory corruption.
  3. Design memory-mapped I/O usage patterns (sequential vs. random access) with awareness that random access to a huge memory-mapped file can generate a high major fault rate if the working set exceeds available page cache.
  4. Ensure adequate physical memory sizing for workloads with large, actively-used working sets to keep major fault rates — and by extension, the risk of thrashing — low.

Summary

A page fault is a hardware-generated trap signaling that a virtual memory access couldn’t be immediately satisfied by the current page table state, requiring operating system intervention. Far from being inherently an error, the vast majority of page faults — minor faults arising from demand paging, copy-on-write, and lazy zero-filled allocation — are a completely routine and essential part of how virtual memory delivers both efficiency and process isolation. Only invalid faults, arising from genuinely illegitimate memory accesses, represent real bugs. Understanding the distinction between minor, major, and invalid faults — and knowing how to measure each — is essential for diagnosing everything from mundane performance tuning to serious memory-pressure incidents.

Frequently Asked Questions

Q: Is a page fault always a bad thing? No. Minor page faults are completely normal and happen constantly as part of healthy virtual memory operation. Only major faults (indicating memory pressure) and invalid faults (indicating a genuine bug) warrant concern.

Q: What’s the difference between a page fault and a segmentation fault? A segmentation fault (SIGSEGV) is specifically the outcome delivered to a process when a page fault turns out to be invalid — an illegitimate memory access. Not all page faults are segmentation faults; most are legitimate and resolved transparently without the process ever “knowing” a fault occurred.

Q: Can page faults occur in kernel mode, not just user programs? Yes. The kernel itself can trigger page faults, for example when accessing pageable kernel memory or handling memory-mapped device I/O. Kernel-mode invalid faults are especially serious, often resulting in a kernel panic (Linux/UNIX) or a Blue Screen of Death / Bug Check (Windows), since there’s no higher-privilege layer to safely terminate.

Q: How does the OS know whether a faulting address is valid or invalid? The OS consults the process’s memory map (Linux calls these Virtual Memory Areas, or VMAs; Windows uses Virtual Address Descriptors, or VADs) to check whether the faulting address falls within any region the process has legitimately been granted, and what permissions apply there.

Q: Why does the faulting instruction get restarted rather than just resumed mid-way? CPU architectures are generally designed so that instructions are either fully completed or have no effect if interrupted by a fault — this atomicity guarantee means the OS can safely resolve the fault and simply re-run the exact same instruction from scratch, without needing to reconstruct any partial execution state.

References

  • Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A, Chapter 4.7 (Page-Fault Exceptions)
  • Silberschatz, Galvin, Gagne — Operating System Concepts, Chapter on Virtual Memory
  • Linux kernel source and documentation — mm/memory.c, Documentation/admin-guide/mm/
  • Microsoft Docs — Page Fault handling and Structured Exception Handling
  • Love, R. — Linux Kernel Development, Chapter on Memory Management
Total
0
Shares

Leave a Reply

Previous Post
Explain the difference between logical and physical address space

Explain the Difference Between Logical and Physical Address Space

Next Post
Describe the working of demand paging

Describe the working of demand paging

Related Posts