Configure Transparent HugePages on RHEL 8–10: always, madvise or never

Tested on Rocky Linux 10.2 (Red Quartz)
Package grubby 8.40
tuned
Applies to RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora
Privilege sudo or root
Scope Check, disable or set Transparent HugePages to madvise on RHEL 8–10, Rocky Linux, AlmaLinux, CentOS Stream and Oracle Linux.
Related guides HugePages vs Transparent HugePages
how to check Transparent HugePages in Linux
GRUB2 and grubby guide
Transparent HugePages decision guide
Configure static HugePages on RHEL 7

Transparent HugePages let the kernel back eligible memory regions with larger pages automatically. Larger pages can reduce translation lookaside buffer misses, but THP allocation and memory compaction can also introduce latency for some workloads.

RHEL 8, 9, and 10 enable THP by default and support always, madvise, and never through runtime sysfs settings, TuneD, kernel command-line parameters, or a systemd unit. never is not automatically the best setting. Follow the current recommendation for your exact application version and validate the result with workload testing.

IMPORTANT
Do not disable Transparent HugePages automatically. Choose always, madvise, or never according to the current guidance for your application version and confirm the result with workload testing. See the Transparent HugePages decision guide for database-specific recommendations and performance considerations.

Transparent HugePages modes compared

Mode Kernel behavior Typical reason to use it
always Kernel attempts to use THP for eligible memory regions Workloads known to benefit from automatic huge-page allocation
madvise THP is primarily used for memory regions explicitly marked by applications Selective use without system-wide aggressive allocation
never Disables automatic THP allocation through the normal system policy Application guidance requires it or testing shows latency problems
defrag setting Controls memory compaction policy for obtaining huge pages Tune allocation latency separately from the main THP mode

enabled and defrag are related but separate controls.

Transparent HugePages Static HugeTLB
Automatically allocated by the kernel Reserved explicitly
Normally backs anonymous memory automatically Applications must be configured to use the reserved pool
Swappable in supported scenarios Reserved HugeTLB memory is normally non-swappable
Controlled through THP sysfs and boot options Controlled with hugepages, hugepagesz and related settings

For the full comparison, see HugePages vs Transparent HugePages.


Check the current THP mode and usage

Read the allocation mode first.

bash
cat /sys/kernel/mm/transparent_hugepage/enabled

Sample output:

output
[always] madvise never

The value in square brackets is the active mode.

Check the compaction policy separately.

bash
cat /sys/kernel/mm/transparent_hugepage/defrag

Sample output:

output
always defer defer+madvise [madvise] never

Check shared-memory THP policy when the kernel exposes it:

bash
if [[ -f /sys/kernel/mm/transparent_hugepage/shmem_enabled ]]; then
  cat /sys/kernel/mm/transparent_hugepage/shmem_enabled
fi

Inspect the running kernel command line.

bash
cat /proc/cmdline

Sample output:

output
BOOT_IMAGE=(hd0,gpt2)/vmlinuz-6.12.0-211.28.1.el10_2.x86_64 root=/dev/mapper/rlm-root ro resume=UUID=26765c90-fea0-4216-9293-9936cabf9135 rd.lvm.lv=rlm/root

Check the default boot entry when no explicit transparent_hugepage= argument is present.

bash
grubby --info="$(grubby --default-kernel)"

Check whether TuneD is managing host tuning.

bash
systemctl is-active tuned

Sample output:

output
active
bash
tuned-adm active

Sample output:

output
Current active profile: balanced

Review current THP memory counters.

bash
grep -E 'AnonHugePages|ShmemHugePages|FileHugePages' /proc/meminfo

Sample output:

output
AnonHugePages:    399360 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
bash
grep -E 'nr_anon_transparent_hugepages|thp_' /proc/vmstat

Sample output:

output
nr_anon_transparent_hugepages 195
thp_migration_success 0
thp_migration_fail 0
thp_migration_split 0
thp_fault_alloc 81100

On newer RHEL 10 kernels, check whether multi-size THP directories are available:

bash
find /sys/kernel/mm/transparent_hugepage \
  -maxdepth 1 \
  -type d \
  -name 'hugepages-*' \
  -print

Sample output:

output
/sys/kernel/mm/transparent_hugepage/hugepages-2048kB
/sys/kernel/mm/transparent_hugepage/hugepages-1024kB
/sys/kernel/mm/transparent_hugepage/hugepages-512kB

View the anonymous THP count for each supported page size:

bash
grep -H . \
  /sys/kernel/mm/transparent_hugepage/hugepages-*/stats/nr_anon \
  2>/dev/null

Sample output:

output
/sys/kernel/mm/transparent_hugepage/hugepages-2048kB/stats/nr_anon:195
/sys/kernel/mm/transparent_hugepage/hugepages-1024kB/stats/nr_anon:0

Check the per-size allocation policy:

bash
grep -H . \
  /sys/kernel/mm/transparent_hugepage/hugepages-*/enabled \
  2>/dev/null

The top-level enabled file primarily describes the global anonymous-memory policy. On newer kernels, also inspect shmem_enabled and each hugepages-*/enabled file. A top-level value of [never] does not by itself prove that every form and size of THP is disabled.

AnonHugePages and VM counters show current or historical usage. AnonHugePages in /proc/meminfo primarily reports traditional PMD-sized anonymous THP. Use the per-size statistics when multi-size THP is available. AnonHugePages: 0 kB does not by itself prove THP is disabled, and non-zero usage can remain after a runtime change until existing processes release or remap their memory. For per-process usage, see how to check Transparent HugePages in Linux.


Change Transparent HugePages temporarily

Runtime changes take effect immediately for new allocation decisions but do not survive reboot.

Set always:

bash
echo always | sudo tee \
  /sys/kernel/mm/transparent_hugepage/enabled

Set madvise:

bash
echo madvise | sudo tee \
  /sys/kernel/mm/transparent_hugepage/enabled

Disable automatic anonymous THP allocation through the top-level policy:

bash
echo never | sudo tee \
  /sys/kernel/mm/transparent_hugepage/enabled

To also disable direct memory compaction during a latency-sensitive test, set the THP defrag policy to never.

bash
echo never | sudo tee \
  /sys/kernel/mm/transparent_hugepage/defrag

Verify both values after a temporary change.

bash
cat /sys/kernel/mm/transparent_hugepage/enabled
bash
cat /sys/kernel/mm/transparent_hugepage/defrag

Sample output after setting never:

output
always madvise [never]
NOTE
Changing the runtime mode does not split every huge page already mapped by running processes. Restart the affected application before comparing memory counters or performance results.

Configure THP permanently with grubby

grubby is the supported persistent method on current RHEL-family releases with GRUB Boot Loader Specification entries.

Inspect all boot entries before changing kernel arguments.

bash
grubby --info=ALL | grep -E '^kernel=|^args='

Sample output:

output
kernel="/boot/vmlinuz-6.12.0-211.28.1.el10_2.x86_64"
args="ro resume=UUID=26765c90-fea0-4216-9293-9936cabf9135 rd.lvm.lv=rlm/root"
kernel="/boot/vmlinuz-6.12.0-211.16.1.el10_2.0.1.x86_64"
args="ro resume=UUID=26765c90-fea0-4216-9293-9936cabf9135 rd.lvm.lv=rlm/root"

Remove an existing THP argument before changing modes.

bash
sudo grubby \
  --remove-args="transparent_hugepage" \
  --update-kernel=ALL

Permanently disable THP

bash
sudo grubby \
  --args="transparent_hugepage=never" \
  --update-kernel=ALL

Permanently set THP to madvise

bash
sudo grubby \
  --args="transparent_hugepage=madvise" \
  --update-kernel=ALL

Permanently enable THP

bash
sudo grubby \
  --args="transparent_hugepage=always" \
  --update-kernel=ALL

--update-kernel=ALL updates every installed boot entry so an older kernel does not boot with a different THP mode.

Verify before reboot:

bash
grubby --info=ALL | grep -E '^kernel=|transparent_hugepage'

Reboot to apply the boot-time setting:

bash
sudo reboot

Red Hat documents persistent THP changes with grubby using transparent_hugepage=always, transparent_hugepage=madvise, or transparent_hugepage=never, followed by a reboot.

Do not use grub2-editenv - set ... or manually rewrite the entire kernelopts value on current GRUB/BLS systems. That approach is error-prone and can remove unrelated kernel arguments. When using grubby as shown here, do not also run grub2-mkconfig; use one boot-argument management method consistently.

For general kernel-argument management on RHEL 8 and later, see the GRUB2 and grubby guide. This article does not cover the legacy RHEL 7 bootloader workflow.


Check TuneD for conflicting THP settings

TuneD profiles can configure THP persistently and may restore a value that differs from a manually selected mode.

Identify the active profile:

bash
tuned-adm active

Record the active profile before creating or enabling custom-thp; you will need it when restoring the previous configuration.

Inspect the active profile and included profiles:

bash
tuned-adm profile_info

Search TuneD configuration for THP settings:

bash
grep -RniE \
  'transparent_hugepages|transparent_hugepage' \
  /etc/tuned /usr/lib/tuned /usr/lib/tuned/profiles

Sample output on Rocky Linux 10.2:

output
/usr/lib/tuned/profiles/network-latency/tuned.conf:10:transparent_hugepages=never
/usr/lib/tuned/profiles/throughput-performance/tuned.conf:40:transparent_hugepages=never
/usr/lib/tuned/profiles/hpc-compute/tuned.conf:12:transparent_hugepages=always

If TuneD should own the setting, create an administrator-managed custom profile rather than editing files under /usr/lib/tuned.

RHEL 10 and equivalent TuneD releases

Create the profile directory:

bash
sudo mkdir -p /etc/tuned/profiles/custom-thp

Create /etc/tuned/profiles/custom-thp/tuned.conf with:

ini
[main]
include=balanced

[vm]
transparent_hugepages=never

[bootloader]
cmdline=transparent_hugepage=never

throughput-performance already sets transparent_hugepages=never in its [vm] section. Inheriting that profile while adding a different bootloader argument can produce conflicting THP policy. Use balanced or another base profile that does not already set THP unless you intend to match its value in both [vm] and [bootloader].

Activate the profile:

bash
sudo tuned-adm profile custom-thp

Reboot so the bootloader argument takes effect:

bash
sudo reboot

Verify:

bash
tuned-adm active
bash
cat /proc/cmdline
bash
cat /sys/kernel/mm/transparent_hugepage/enabled

For madvise or always, replace never consistently in both the [vm] and [bootloader] sections.

RHEL 8 and RHEL 9 path

On the traditional TuneD layout, create the profile at:

output
/etc/tuned/custom-thp/tuned.conf

RHEL 10 stores distribution profiles under /usr/lib/tuned/profiles and custom profiles under /etc/tuned/profiles. Older RHEL documentation uses /usr/lib/tuned and /etc/tuned. A TuneD bootloader profile requires a reboot before its kernel argument takes effect.

Do not configure one mode through TuneD and another through a separate startup service. Database-specific TuneD profiles may intentionally modify THP. The primary persistent method in this article remains grubby unless your site standardizes on TuneD.


Verify THP after reboot

Verify the active kernel argument:

bash
cat /proc/cmdline

Verify the configured mode:

bash
cat /sys/kernel/mm/transparent_hugepage/enabled

Verify the compaction setting:

bash
cat /sys/kernel/mm/transparent_hugepage/defrag

When present, also verify shared-memory THP policy:

bash
if [[ -f /sys/kernel/mm/transparent_hugepage/shmem_enabled ]]; then
  cat /sys/kernel/mm/transparent_hugepage/shmem_enabled
fi

Check the default boot entry:

bash
grubby --info="$(grubby --default-kernel)"

Check current usage:

bash
grep AnonHugePages /proc/meminfo
bash
grep nr_anon_transparent_hugepages /proc/vmstat
Result Meaning
always madvise [never] Automatic anonymous THP allocation is disabled by the top-level policy
always [madvise] never Applications can request THP selectively
[always] madvise never THP is enabled generally
AnonHugePages: 0 kB No anonymous THP currently counted; not proof of configuration
Non-zero AnonHugePages after disabling Existing processes may still hold THP mappings

Restart the workload after changing THP before comparing application behavior.


Restore the default or change modes

If a custom TuneD profile controls THP, switch away from it first:

bash
sudo tuned-adm profile <previous-profile>

Replace <previous-profile> with the profile reported by tuned-adm active before you enabled custom-thp. Use balanced only when it was the original profile.

Alternatively, remove the THP settings from the custom profile and reactivate it.

Then remove the explicit kernel argument:

bash
sudo grubby \
  --remove-args="transparent_hugepage" \
  --update-kernel=ALL

Reboot:

bash
sudo reboot

Removing the kernel argument restores the distribution kernel default only when no active TuneD profile, systemd unit, or configuration-management policy applies another THP setting.

To switch directly from one explicit mode to another, remove the existing parameter first and then add the new value. That avoids duplicate kernel arguments such as:

text
transparent_hugepage=never transparent_hugepage=madvise

Troubleshoot THP configuration

THP still shows always after reboot

Check the boot command line and boot entries:

bash
cat /proc/cmdline
bash
grubby --info=ALL | grep -E '^kernel=|transparent_hugepage'
bash
tuned-adm active

Possible causes include a parameter added only to one kernel entry, booting the wrong kernel, a TuneD override, duplicate THP arguments, skipping reboot, or a custom systemd service overwriting the setting after boot.

AnonHugePages remains non-zero

Existing mappings are not necessarily removed immediately. Restart the application and check again. A non-zero value does not by itself mean the boot setting failed unless /sys/kernel/mm/transparent_hugepage/enabled also shows the wrong mode.

enabled and defrag show different values

They control different decisions. enabled controls when THP allocations are permitted. defrag controls how aggressively the kernel compacts memory to satisfy them. They do not have to display the same active value.

The parameter disappears after a kernel update

Confirm the argument was applied with --update-kernel=ALL, then inspect whether TuneD or configuration-management tools replace boot arguments after package updates.

bash
grubby --info=ALL

Application documentation conflicts with this article

Follow the current documentation for the exact application version and operating-system kernel, then benchmark the workload. See the Transparent HugePages decision guide for workload-specific recommendations.

Symptom Likely cause Main check
Wrong mode after reboot Kernel argument missing or TuneD override /proc/cmdline, tuned-adm active
Duplicate modes Old argument not removed grubby --info=ALL
Usage remains non-zero Existing mappings Restart workload
Latency remains high Compaction or unrelated memory pressure Check defrag, VM counters and workload metrics
New kernel behaves differently Boot entries differ grubby --info=ALL

Conclusion

Do not disable Transparent HugePages automatically. Choose always, madvise, or never using the Transparent HugePages decision guide, use sysfs for temporary testing, use grubby for persistent RHEL 8–10 configuration, and check TuneD for conflicting policy. Verify the active mode separately from current THP usage and restart affected applications before comparing results.

References


Frequently Asked Questions

1. Should Transparent HugePages always be disabled on database servers?

No. The correct mode depends on the database version, memory allocator, kernel and vendor guidance. Some current products recommend enabling THP or setting it to madvise, while older releases may recommend never.

2. What is the difference between THP madvise and never?

madvise permits THP primarily for memory regions explicitly requested by applications. never disables automatic THP allocation through the normal global policy, although newer kernels can still honor explicit operations such as MADV_COLLAPSE.

3. Why is AnonHugePages still non-zero after disabling THP?

Running processes can retain huge pages allocated before the setting changed. Restart the affected workload and verify the active mode in /sys/kernel/mm/transparent_hugepage/enabled.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)