Memory on Linux is managed in pages, normally 4 KB each. A server with 16 GB of RAM has millions of them, and translating addresses for all those pages costs CPU time. Huge pages (typically 2 MB) reduce that overhead. There are two mechanisms: static HugePages (reserved explicitly) and Transparent Huge Pages (THP) (automatic). Databases have strong opinions about both.
Why it matters
- The CPU caches address translations in the TLB (translation lookaside buffer). With bigger pages, fewer entries cover more memory, so there are fewer TLB misses, which helps large-memory workloads.
- But THP’s background work (compacting memory to create huge pages, and splitting them) can cause latency spikes and memory bloat for some databases.
Check the current THP setting
cat /sys/kernel/mm/transparent_hugepage/enabled
# [always] madvise never ← the bracketed value is active
cat /sys/kernel/mm/transparent_hugepage/defrag
grep -i huge /proc/meminfo
| Value | Meaning |
|---|---|
always |
Kernel uses huge pages wherever it can |
madvise |
Only for memory regions where the application asks (madvise()) |
never |
Disabled |
Ubuntu and Debian default to madvise on recent releases. Others may use always.
What databases recommend
| Software | Recommendation (check current docs for your version) |
|---|---|
| Redis / Valkey | Disable THP (never); Redis logs a warning when THP is always (latency and copy-on-write memory issues during persistence) |
| MongoDB | Historically disable THP; newer versions (8.0+) recommend enabling it. Follow your version’s production notes |
| PostgreSQL | THP madvise or never; optionally use static HugePages via huge_pages = try |
| MySQL / MariaDB | Usually disable THP; static large pages optional |
| Java apps | Optional: -XX:+UseTransparentHugePages or static pages |
madvise is a good general default: applications that benefit can opt in, and others are unaffected.
Change THP at runtime
echo madvise | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
echo defer+madvise | sudo tee /sys/kernel/mm/transparent_hugepage/defrag
Make it permanent
Option 1: kernel command line (GRUB):
sudo sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT="/&transparent_hugepage=madvise /' /etc/default/grub
sudo update-grub && sudo reboot
Option 2: a small systemd unit that sets it at boot:
# /etc/systemd/system/thp-madvise.service
[Unit]
Description=Set THP to madvise
After=sysinit.target local-fs.target
Before=redis-server.service mongod.service postgresql.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled'
[Install]
WantedBy=basic.target
sudo systemctl daemon-reload && sudo systemctl enable --now thp-madvise
See systemd unit files.
Static HugePages (PostgreSQL example)
Reserve huge pages for PostgreSQL’s shared memory:
# PostgreSQL 15+: how many pages it needs (server stopped or using -C)
sudo -u postgres /usr/lib/postgresql/16/bin/postgres -D /var/lib/postgresql/16/main -C shared_memory_size_in_huge_pages
echo "vm.nr_hugepages = 1100" | sudo tee /etc/sysctl.d/60-hugepages.conf
sudo sysctl --system
In postgresql.conf: huge_pages = try (or on, to fail if unavailable). Restart PostgreSQL, and check HugePages_Free in /proc/meminfo.
Reserved huge pages are unavailable to other programs, even when unused. Only reserve what the database needs. See PostgreSQL performance tuning.
On a VPS
THP and HugePages work inside a KVM VPS, since you control your own kernel. Gains are most noticeable for databases with large buffer pools (several GB). For small instances, leaving THP at madvise is the sensible choice. See what is KVM virtualization.
Quick reference
| Task | Command / file |
|---|---|
| THP status | cat /sys/kernel/mm/transparent_hugepage/enabled |
| Set THP now | echo madvise | sudo tee …/enabled |
| Permanent | GRUB transparent_hugepage=madvise or systemd unit |
| Huge page stats | grep -i huge /proc/meminfo |
| Reserve static pages | vm.nr_hugepages in sysctl |
Related: Redis maxmemory and eviction and Linux memory usage.