Huge pages reduce the overhead of virtual memory management by using larger memory page sizes — typically 2 MB instead of the default 4 KB. For memory-intensive databases such as Oracle, PostgreSQL, and MySQL, huge pages eliminate millions of Translation Lookaside Buffer (TLB) misses per second, lower page table walk overhead, and prevent the kernel from paging out critical shared memory segments. On RHEL 8 there are two distinct huge page mechanisms: Transparent Huge Pages (THP), which the kernel manages automatically, and explicit (static) huge pages, which the administrator reserves at boot time and which databases can map directly for maximum predictability. This tutorial covers both approaches and how to calculate the right allocation for your workload.

Prerequisites

  • A RHEL 8 server with root or sudo access
  • Sufficient free RAM to dedicate to the huge page pool
  • A database workload (Oracle, PostgreSQL, or MySQL) whose memory footprint you know in advance
  • The tuned package installed (included in RHEL 8 by default)

Step 1 — Inspect the Current Transparent Huge Page Configuration

RHEL 8 ships with Transparent Huge Pages enabled by default. While THP is beneficial for some workloads, most databases recommend disabling it because THP compaction can cause unpredictable latency spikes and increased CPU usage during defragmentation.

# Check the current THP status
cat /sys/kernel/mm/transparent_hugepage/enabled

# Check the defrag setting
cat /sys/kernel/mm/transparent_hugepage/defrag

# Check current huge page stats in /proc/meminfo
grep -i huge /proc/meminfo

The output of the first command shows three options: always, madvise, and never, with the active choice in square brackets. For most database servers you want to see [never] or [madvise].

Step 2 — Disable Transparent Huge Pages for Databases

The recommended approach on RHEL 8 is to use a custom tuned profile that disables THP, which is cleaner and survives reboots better than editing rc.local.

# Create a custom tuned profile based on throughput-performance
sudo mkdir -p /etc/tuned/database-optimized
sudo tee /etc/tuned/database-optimized/tuned.conf > /dev/null <<'EOF'
[main]
summary=Database-optimized profile: disables THP, raises limits

[bootloader]
cmdline=transparent_hugepage=never

[vm]
transparent_hugepages=never

[include]
= throughput-performance
EOF

# Activate the new profile
sudo tuned-adm profile database-optimized

# Verify THP is disabled immediately (no reboot required for runtime)
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/defrag
cat /sys/kernel/mm/transparent_hugepage/enabled

Step 3 — Calculate Required Explicit Huge Pages

Before reserving huge pages, calculate how many 2 MB pages your database requires. For PostgreSQL, the relevant value is shared_buffers. For Oracle, it is the SGA size. For MySQL InnoDB, it is innodb_buffer_pool_size. Add a 10–15% buffer to the pool size to account for shared memory overhead beyond the primary buffer pool.

# Formula: huge_pages_needed = CEIL( memory_bytes / 2097152 )
# Example: PostgreSQL shared_buffers = 8 GB
python3 -c "import math; print(math.ceil(8 * 1024**3 / 2097152))"
# Output: 4096  (4096 x 2 MB = 8 GB)

# Add 10% overhead buffer
python3 -c "import math; print(math.ceil(8 * 1024**3 * 1.1 / 2097152))"
# Output: 4505

# Check total system RAM to ensure headroom
grep MemTotal /proc/meminfo

Step 4 — Reserve Explicit Huge Pages via sysctl

Set vm.nr_hugepages to the number calculated in the previous step. Reserve pages as early as possible after boot, before memory becomes fragmented, to maximize the chance of successful allocation.

# Apply immediately (runtime)
sudo sysctl -w vm.nr_hugepages=4505

# Make persistent across reboots
echo "vm.nr_hugepages = 4505" | sudo tee /etc/sysctl.d/99-hugepages.conf

# Confirm allocation succeeded
grep -i huge /proc/meminfo

# Expected output (HugePages_Total should equal 4505):
# HugePages_Total:    4505
# HugePages_Free:     4505
# HugePages_Rsvd:        0
# HugePages_Surp:        0
# Hugepagesize:       2048 kB

If HugePages_Total is less than the requested value, the kernel could not allocate enough contiguous memory. Either reboot with the parameter set early via sysctl.d, or reduce the number and supplement with THP set to madvise.

Step 5 — Configure PostgreSQL to Use Huge Pages

PostgreSQL uses the mmap or shmem interface to request huge pages. Set huge_pages = on in postgresql.conf and ensure the hugepage group permissions allow the postgres user to map shared memory.

# Find the hugepages group ID
cat /proc/meminfo | grep HugePages
grep -i hugepage /proc/sys/vm/hugetlb_shm_group || echo "0"

# Allow the postgres group to use hugepages via sysctl
PG_GID=$(id -g postgres)
echo "vm.hugetlb_shm_group = $PG_GID" | sudo tee -a /etc/sysctl.d/99-hugepages.conf
sudo sysctl -w vm.hugetlb_shm_group=$PG_GID

# Edit postgresql.conf
sudo -u postgres sed -i "s/#huge_pages = try/huge_pages = on/" /var/lib/pgsql/data/postgresql.conf

# Restart PostgreSQL
sudo systemctl restart postgresql

# Verify usage — HugePages_Rsvd should increase
grep -i huge /proc/meminfo

Step 6 — Verify Huge Page Mapping in Process Memory

Confirm that the database process is actually using huge pages by inspecting its memory maps.

# Get the PostgreSQL postmaster PID
PG_PID=$(pgrep -o postgres)

# Check for huge page mappings (look for "huge" in smaps)
sudo grep -i huge /proc/$PG_PID/smaps | head -20

# Summarize huge page usage for the process
sudo grep AnonHugePages /proc/$PG_PID/smaps | awk '{sum+=$2} END {print sum/1024 " MB used via AnonHugePages"}'

Conclusion

You have disabled Transparent Huge Pages using a custom tuned profile to prevent latency spikes, calculated the correct explicit huge page reservation for your database’s memory footprint, applied the setting persistently via /etc/sysctl.d/99-hugepages.conf, and configured PostgreSQL to map shared memory using those reserved pages. Database workloads typically see a 5–20% reduction in CPU time spent on memory management after this change, with the largest gains on servers handling many short transactions per second where TLB pressure was previously high.

Next steps: How to Tune Linux Kernel Parameters with sysctl on RHEL 8, How to Profile Application Performance with perf on RHEL 8, and How to Configure NUMA-Aware Memory Allocation for Databases on RHEL 8.