Comparing transparent and explicit huge pages
Transparent Huge Pages sound like a free performance win, since the kernel forms larger memory pages on its own without requiring any application changes. On database and cache servers, that very automation regularly turns out to be a source of unpredictable latency spikes, while statically reserved huge pages offer a very different, far more controllable behavior.
Table of Contents
- 1. Memory page fundamentals: why bigger pages help at all
- 2. Explicit huge pages through HugeTLB
- 3. How Transparent Huge Pages work automatically
- 4. Why THP causes latency spikes on databases
- 5. Checking THP status and mode through sysfs
- 6. Disabling THP for MySQL and Redis
- 7. Explicit huge pages as an alternative for the InnoDB buffer pool
- 8. Monitoring: how to spot THP related latency issues
- 9. Best practice checklist for database and cache servers
- 10. Summary
- 11. FAQ
1. Memory page fundamentals: why bigger pages help at all
The kernel manages physical memory in fixed size pages, 4 kilobytes by default on x86_64 systems. Every access a process makes to virtual memory has to be translated into a physical address through the CPU's memory management unit, for which the translation lookaside buffer, or TLB, serves as a fast cache for recently used address translations.
For applications with very large memory footprints, such as a database buffer pool spanning several dozen gigabytes, the limited number of TLB entries at 4 kilobyte pages is not enough to cover the entire active memory range, leading to frequent TLB misses and, as a result, additional, slower page table lookups. Larger pages, such as 2 megabytes, reduce the number of TLB entries needed for the same memory range by a factor of 512, noticeably cutting the number of TLB misses.
2. Explicit huge pages through HugeTLB
HugeTLB huge pages get reserved as a fixed count out of available memory at boot time or at runtime, and from that point on are exclusively available to applications that explicitly request them through the shmget system call with the SHM_HUGETLB flag or through a mounted hugetlbfs filesystem. This reservation is static: once memory has been reserved for huge pages, it is no longer available to applications that cannot use huge pages, even while it sits idle.
The big advantage of this static behavior is predictability: once successfully reserved, the pages stay stable in memory for the entire runtime, without the kernel having to merge, split, or move pages in the background. The downside is administrative overhead, since the right number of huge pages has to be calculated up front and reserved through /proc/sys/vm/nr_hugepages or a kernel parameter at boot, which either wastes memory or falls short if sized incorrectly.
# Check the current huge page status
grep Huge /proc/meminfo
# Reserve 4096 huge pages at 2 MB each permanently (equals 8 GB)
echo 4096 | sudo tee /proc/sys/vm/nr_hugepages
# Persist it for future boots via sysctl.conf
echo "vm.nr_hugepages = 4096" | sudo tee -a /etc/sysctl.d/99-hugepages.conf
3. How Transparent Huge Pages work automatically
Transparent Huge Pages, or THP, take a fundamentally different approach: instead of an explicit reservation by the application, the kernel thread khugepaged continuously scans the memory regions of every process and automatically merges several contiguous 4 kilobyte pages into one 2 megabyte huge page in the background, whenever it finds a suitable, sufficiently contiguous region, without the application noticing anything about it.
This automation works deliberately transparently, meaning without any code change to the affected application, which makes THP attractive at first glance. But the crucial difference from HugeTLB lies exactly in this automation: the kernel has to continuously analyze memory regions, and where necessary defragment fragmented memory through memory compaction to even form contiguous 2 megabyte blocks, and this work happens while the system is running, not once at boot.
# Show the current THP status and mode
cat /sys/kernel/mm/transparent_hugepage/enabled
# Output looks like: always [madvise] never
# Watch khugepaged activity while the system is running
cat /sys/kernel/mm/transparent_hugepage/khugepaged/pages_collapsed
4. Why THP causes latency spikes on databases
The actual problem shows up whenever khugepaged becomes active on heavily fragmented memory: to obtain a contiguous 2 megabyte region, the kernel has to move existing pages through memory compaction, which costs CPU time and, in unfavorable cases, blocks the accessing process for the duration of the operation. On a MySQL server with a large InnoDB buffer pool, this shows up as a sudden, seemingly unprovoked latency spike in the middle of normal operation, with no obvious external trigger.
The always mode makes the problem worse still, since the kernel then tries to form huge pages for practically every anonymous memory region, regardless of whether the affected application benefits from that at all. For workloads with many small, short lived allocations, as seen with frequent key churn on Redis, this tends to create additional overhead through constant merging and splitting of pages rather than an actual performance gain.
5. Checking THP status and mode through sysfs
The current THP mode can be read from /sys/kernel/mm/transparent_hugepage/enabled, where three values are possible: always enables THP automatically for every suitable memory region, madvise only forms huge pages where an application explicitly requests it through the madvise system call with the MADV_HUGEPAGE flag, and never disables THP entirely.
Beyond the plain enabled status, it is worth checking /sys/kernel/mm/transparent_hugepage/defrag, which controls how aggressively the kernel helps out with compaction when contiguous memory is missing. A value of defer+madvise pushes the expensive defragmentation work onto a background kthread instead of running it synchronously in the application's access path, already noticeably softening many of the worst latency spikes without disabling THP entirely.
# Check THP enabled mode and defrag behavior together
cat /sys/kernel/mm/transparent_hugepage/enabled
cat /sys/kernel/mm/transparent_hugepage/defrag
# Anonymous huge pages currently in use by THP on the running system
grep AnonHugePages /proc/meminfo
6. Disabling THP for MySQL and Redis
Both the MySQL and Redis operator documentation consistently recommend setting THP to never on servers running these services, since both workloads typically manage large, long lived memory regions with irregular access patterns, where the khugepaged automation causes more harm through latency spikes than it delivers in TLB miss reduction.
A change through echo never into the sysfs file takes effect immediately but does not survive a reboot, so the setting has to be pinned permanently through a systemd service, an rc.local entry, or a kernel parameter at boot. The most reliable approach on modern systems is a dedicated systemd oneshot service that runs automatically on every boot, instead of relying on a manually maintained init script.
# /etc/systemd/system/disable-thp.service
cat <<'EOF' | sudo tee /etc/systemd/system/disable-thp.service
[Unit]
Description=Disable Transparent Huge Pages (THP)
After=sysinit.target local-fs.target
Before=mysql.service redis.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled'
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/defrag'
[Install]
WantedBy=basic.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now disable-thp.service
7. Explicit huge pages as an alternative for the InnoDB buffer pool
Where disabling the automation removes THP's contribution entirely, MySQL can still benefit from large pages, but through the opposite, explicit route: with the large-pages option in the MySQL configuration and HugeTLB memory reserved up front through nr_hugepages, InnoDB places its buffer pool deliberately in stable, non swappable huge pages, without the kernel being able to change that allocation at runtime anymore.
This explicit variant requires a bit more upfront planning, since the number of reserved huge pages has to match the actual buffer pool size and the reserved memory stays blocked off for other applications, but in return it delivers noticeably more predictable behavior with none of the compaction related latency risk that THP can introduce at runtime.
8. Monitoring: how to spot THP related latency issues
A reliable first indicator is a rising value for compact_stall and thp_collapse_alloc in /proc/vmstat, which respectively show how often a process had to wait for an ongoing memory compaction operation and how often khugepaged actually merged pages. A continuously rising compact_stall value alongside irregular latency spikes observed in the application is a strong sign that THP is the cause.
Beyond that, perf stat with the page-faults event, along with a direct look at AnonHugePages in /proc/meminfo over time, gives a clearer picture of whether and how strongly THP is actually active on a particular server, rather than relying solely on the static configuration under sysfs, which says nothing about khugepaged's actual runtime activity.
# Watch compaction stalls and THP collapse events over time
watch -n 2 "grep -E 'compact_stall|thp_collapse_alloc' /proc/vmstat"
# Amount of memory currently held by THP
grep AnonHugePages /proc/meminfo
9. Best practice checklist for database and cache servers
On every server running MySQL, MariaDB, PostgreSQL, or Redis in production, THP should be set to never through a permanent systemd service, rather than relying on the distribution's default, which on many systems still ships as madvise or even always.
Where the extra TLB benefit of large pages is still desired, for example for a very large InnoDB buffer pool, the path goes through explicit HugeTLB huge pages with a carefully calculated nr_hugepages reservation, not through re enabling THP, since only the explicit variant consistently avoids the latency risk introduced by the kernel's automation.
| Trait | Transparent Huge Pages | Explicit Huge Pages (HugeTLB) |
|---|---|---|
| Reservation | Automatic in the background via khugepaged | Static, reserved up front via nr_hugepages |
| Configuration effort | Low, but hard to predict | Higher, requires capacity planning |
| Latency risk | Present due to runtime memory compaction | Essentially none once successfully reserved |
| Recommendation for MySQL/Redis | Disable (never) | Optionally enable via large-pages |
| Memory usage by other processes | Stays flexibly available | Reserved memory blocked exclusively |
Mironsoft
Server administration, Docker hosts, and performance tuning
Linux servers nobody on the team really understands anymore?
We handle setup, hardening, and performance tuning of Linux servers and Docker hosts for Magento deployments, documented and traceable instead of grown and unclear.
Server Audit
Review the existing server configuration for security gaps and performance bottlenecks.
Docker Host Setup
Set up and secure production-ready Docker environments for Magento cleanly.
Monitoring & Tuning
Measure resource usage and tune systemd, kernel, and services with purpose.
10. Summary
THP vs. Huge Pages
THP
Automatic through khugepaged, risky for large database buffer pools
HugeTLB
Statically reserved, predictable, requires upfront capacity planning
Recommendation
Set THP to never for MySQL, MariaDB, PostgreSQL, and Redis
Verification
Status and mode checkable under /sys/kernel/mm/transparent_hugepage