Transparent Huge Pages vs. Explicit Huge Pages: Differences and Tuning for Database Servers
AI generated
$
/etc
Linux
THP vs. Huge Pages
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.

9 min read Linux Kernel Performance

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

11. FAQ: THP vs. Huge Pages

1What is the fundamental difference between THP and explicit huge pages?
THP forms large pages automatically in the background through the kernel thread khugepaged, without any application change. Explicit huge pages through HugeTLB, on the other hand, get reserved statically up front and requested deliberately by the application through shmget or hugetlbfs.
2Why does THP cause latency spikes on databases?
When khugepaged wants to form a contiguous 2 megabyte region on fragmented memory, the kernel has to move existing pages through memory compaction, which can block the accessing process for the duration of the operation. This happens especially often with large buffer pools that have irregular access patterns.
3How do I disable THP permanently?
Through echo never into /sys/kernel/mm/transparent_hugepage/enabled and /defrag, pinned by a systemd oneshot service that runs automatically on every boot, since the plain sysfs change alone does not survive a reboot.
4Should I disable THP for Redis?
Yes, the official Redis documentation explicitly recommends never, since the khugepaged automation, under frequent key churn with many small, short lived allocations, creates more overhead through merging and splitting pages than it delivers in TLB benefits.
5What does the madvise mode mean for THP?
In madvise mode, the kernel only forms huge pages for memory regions an application explicitly requests through the madvise system call with the MADV_HUGEPAGE flag, rather than acting automatically on practically every suitable anonymous memory region as in always mode.
6Can I still benefit from large memory pages with THP disabled?
Yes, through explicit HugeTLB huge pages, reserved up front with nr_hugepages and used deliberately by MySQL for the InnoDB buffer pool via the large-pages option, without the latency risk that automatic THP management can introduce.
7How do I tell whether THP is actually responsible for latency issues?
A rising compact_stall value in /proc/vmstat, combined with irregular latency spikes observed in the application, is a strong indicator. AnonHugePages in /proc/meminfo additionally shows how much memory is currently actually held by THP.
8Why isn't a one time echo never change enough?
The change only applies to the running system and does not survive a reboot, since the value under sysfs resets to the kernel default at startup. Persistence requires a systemd service or a comparable boot hook.
9Does reserved HugeTLB memory block other applications?
Yes, 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 reservation should therefore be carefully sized to the actual buffer pool requirement.
10Does the THP problem also affect PostgreSQL?
PostgreSQL uses shared memory at a similar scale to MySQL and is fundamentally exposed to the same compaction related latency risks. For PostgreSQL servers too, setting THP to never is regularly recommended instead of relying on the distribution default.