Value | Description | Configuration Command |
0 | Do not use huge pages | export GLIBC_TUNABLES=glibc.malloc.hugetlb=0 |
1 | Use Transparent Huge Pages (THP). | export GLIBC_TUNABLES=glibc.malloc.hugetlb=1 |
2 | Use system default huge pages. | export GLIBC_TUNABLES=glibc.malloc.hugetlb=2 |
x(x > 2) | Specify the page size as x (must match a system-supported page size). | export GLIBC_TUNABLES=glibc.malloc.hugetlb=x |
cat /sys/kernel/mm/transparent_hugepage/enabled
always [madvise] never
Mode | Description |
always | Always use transparent huge pages. |
madvise | Use transparent huge pages based on application recommendations. |
never | Never use transparent huge pages. |
always is set, the system-wide policy prioritizes transparent hugepages, which means this feature is enabled by default. If you can accept this setting, you can skip this section. If never is set, use the following command to adjust it:echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
export GLIBC_TUNABLES=glibc.malloc.hugetlb=1
AnonHugePages field in /proc/self/smaps. A non-zero value indicates that the process has used transparent hugepages, which means transparent hugepages have taken effect.cat /proc/meminfo | grep Hugepagesize
Hugepagesize: 2048 kB
nr_hugepages corresponding to hugepages-2048kB:ls /sys/kernel/mm/hugepages
hugepages-1048576kB hugepages-2048kB
echo 520 > /sys/kernel/mm/hugepages/hugepages-2048kB
export GLIBC_TUNABLES=glibc.malloc.hugetlb=2
/proc/self/smaps where Private_Hugetlb is non-zero. You will get logs similar to the following:MMUPageSize: 2048 kBPrivate_Hugetlb: 1050624 kB...MMUPageSize: 2048 kBPrivate_Hugetlb: 2048 kB
MMUPageSize (Memory Management Unit Page Size) is 2048 kB (2 MB), which is consistent with the setting described in the Setting nr_hugepages section. Private_Hugetlb has two blocks: 1050624 kB and 2048 kB:malloc manages memory through chunks. In addition to providing 1 GB of memory, malloc also needs to reserve a chunk header to manage this memory block. Because 2 MB alignment is used in this case, this extra portion is generated.malloc allocates space for the tcache data structure on its first call. Additionally, due to 2 MB alignment, this extra portion is produced.malloc & memset. Reserving only 1 GB is insufficient because, in addition to the 1 GB memory itself, extra 2 MB-aligned space must be reserved for the chunk header and tcache.ls /sys/kernel/mm/hugepages
hugepages-1048576kB hugepages-2048kB
echo 3 > /sys/kernel/mm/hugepages/hugepages-1048576kB
malloc & memset.export GLIBC_TUNABLES=glibc.malloc.hugetlb=1073741824
/proc/self/smaps where Private_Hugetlb is non-zero. You will get logs similar to the following:MMUPageSize: 1048576 kBPrivate_Hugetlb: 2097152 kB...MMUPageSize: 1048576 kBPrivate_Hugetlb: 1048576 kB
MMUPageSize (Memory Management Unit Page Size) is 1048576 kB (1 GB), which is consistent with the setting described in the Setting nr_hugepages section. Private_Hugetlb has two blocks: 2097152 kB and 1048576 kB:malloc still prioritizes carving memory from this space. However, the above example also reveals a drawback of hugepages: improper use can cause significant memory waste, so developers need to plan memory usage carefully./proc/<PID>/smaps output of the process.test_hugepage.c:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#define MEM_SIZE (1UL << 30) /* 1GB */int main(){char *p = malloc(MEM_SIZE);if (!p) {perror("malloc failed");return 1;}printf("PID: %d\\n", getpid());/* Initialize memory to trigger hugepage allocation */memset(p, 0, MEM_SIZE);printf("Allocated and initialized %lu MB of memory. Press Enter to exit...\\n", MEM_SIZE >> 20);getchar();free(p);return 0;}
gcc -o test_hugepage test_hugepage.c
./test_hugepage
cat /proc/<PID>/smaps | grep -E "AnonHugePages|Private_Hugetlb|MMUPageSize"
Huge Page Type | smaps Field | Non-Zero Meaning |
Transparent Huge Pages (hugetlb=1) | AnonHugePages | The process has used transparent huge pages. |
Standard Huge Pages (hugetlb=2 or a custom value) | Private_Hugetlb | The process has used standard huge pages. |
AnonHugePages value indicates that transparent hugepages have taken effect. For standard hugepages, a non-zero Private_Hugetlb value and an MMUPageSize that matches the configured hugepage size indicate that standard hugepages have taken effect.0f982c1827 malloc: Enable huge page support on main arena0849eed45d malloc: Move MORECORE fallback mmap to sysmalloc_mmap_fallbackc1beb51d08 malloc: Add Huge Page support to arenas98d5fcb8d0 malloc: Add Huge Page support for mmap6cc3ccc67e malloc: Move mmap logic to its own function7478c9959a malloc: Add THP/madvise support for sbrk5f6d8d97c6 malloc: Add madvise support for Transparent Huge Pages
malloc call, a function that parses the glibc hugetlb environment variable is invoked. The code is as follows, where value is the user-specified value:static __always_inline intdo_set_hugetlb (size_t value){if (value == 1){enum malloc_thp_mode_t thp_mode = __malloc_thp_mode ();/* Only enable THP madvise usage if system does support it andhas 'madvise' mode. Otherwise the madvise() call is wasteful. */if (thp_mode == malloc_thp_mode_madvise)mp_.thp_pagesize = __malloc_default_thp_pagesize ();}else if (value >= 2)__malloc_hugepage_config (value == 2 ? 0 : value,&mp_.hp_pagesize, &mp_.hp_flags);return 0;}
value is 1, the thp_pagesize value is set by reading /sys/kernel/mm/transparent_hugepage/hpage_pmd_size through the __malloc_default_thp_pagesize function:unsigned long int__malloc_default_thp_pagesize (void){int fd = __open64_nocancel ("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", O_RDONLY);if (fd == -1)return 0;char str[INT_BUFSIZE_BOUND (unsigned long int)];ssize_t s = __read_nocancel (fd, str, sizeof (str));__close_nocancel (fd);if (s == 0)return 0;unsigned long int r = 0;for (ssize_t i = 0; i < s; i++){if (str[i] == '\\n')break;r *= 10;r += str[i] - '0';}return r;}
value is 2, the system default hugepage size is obtained through malloc_default_hugepage_size.value is greater than 2, read /sys/kernel/mm/hugepage to determine whether the input value is a hugepage size supported by the system:void__malloc_hugepage_config (size_t requested, size_t *pagesize, int *flags){*pagesize = 0;*flags = 0;if (requested == 0){*pagesize = malloc_default_hugepage_size ();if (*pagesize != 0)*flags = hugepage_flags (*pagesize);return;}/* Each entry represents a supported huge page in the form of:hugepages-<size>kB. */int dirfd = __open64_nocancel ("/sys/kernel/mm/hugepages",O_RDONLY | O_DIRECTORY, 0);if (dirfd == -1)return;char buffer[1024];while (true){...hpsize *= 1024;if (hpsize == requested){*pagesize = hpsize;*flags = hugepage_flags (*pagesize);__close_nocancel (dirfd);return;}}__close_nocancel (dirfd);}
hugepage_flags is as follows. flags is ultimately passed to mmap to specify the size of standard hugepages:static inline inthugepage_flags (size_t pagesize){return MAP_HUGETLB | (__builtin_ctzll (pagesize) << MAP_HUGE_SHIFT);}
/sys/kernel/mm/transparent_hugepage/enabled is set to madvise, user space must use the madvise system call to tell the kernel the usage pattern of the specified virtual memory. glibc wraps madvise as follows:static inline voidmadvise_thp (void *p, INTERNAL_SIZE_T size){# ifdef MADV_HUGEPAGE/* Do not consider areas smaller than a huge page or if the tunableis not active. */if (mp_.thp_pagesize == 0 || size < mp_.thp_pagesize)return;...__madvise (p, size, MADV_HUGEPAGE);# endif}
thp_pagesize is initialized to the system default transparent hugepage size on the first malloc call. glibc can use transparent hugepages by calling madvise_thp after each mmap.피드백