# Huge pages

Linux maps virtual memory to physical memory in fixed-size chunks called pages. The default is 4 KB. On x86_64 and ARM64 the kernel also supports 2 MB and 1 GB *huge pages*. Switching a large allocation from default pages to huge pages changes two things at once: the number of first-touch page faults shrinks by orders of magnitude, and Translation Lookaside Buffer (TLB) pressure drops sharply.

## The two costs that go down

**Page faults.** Linux uses lazy allocation: a `mmap`'d region notes the allocation, but physical pages are only attached on first access, via a *minor page fault*. A 120 GB region at 4 KB per page has up to 31 million potential first-touch faults; with 2 MB huge pages, ~61,440; with 1 GB huge pages, ~120. Faults aren't free — each one is microseconds in the kernel — and faults that happen at the wrong moment (e.g., while holding a [[spinlock]]) can cascade. See [[linux-7-postgres-regression]] for the canonical case.

**TLB pressure.** The CPU caches recent virtual→physical translations in the TLB. A miss forces a multi-level page-table walk. Larger pages mean fewer entries cover the same working set, so the working set actually fits in the TLB, and the hot path avoids walks.

Both effects are the memory hierarchy leaking into application performance. [[memory-systems-cache-dram-disk]] is the reference for the layer below this one — how SRAM caches are organized, what a DRAM row activation actually costs, and why a page-table walk is expensive in the first place.

## What you give up

Huge pages are pre-allocated and reserved at the OS level. That memory isn't available to other processes whether or not you use it.

Internal fragmentation gets worse. A huge page is allocated as a unit, so a region using a fraction of one wastes the rest.

For long-running, memory-hungry processes — databases, JVMs with large heaps, in-memory caches — the tradeoff usually wins. For everything else it's noise.

## PostgreSQL specifically

PostgreSQL exposes a `huge_pages` parameter with three values: `off`, `on`, `try` (default). `try` silently falls back to 4 KB if huge pages aren't available, which means you can think you have huge pages and not. `on` makes the server fail to start if huge pages aren't configured at the OS level — louder, but you actually know what you're running.
