You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让/dev/shm只读文件通过shm_open/mmap启用Transparent Huge Pages?

如何让/dev/shm映射文件启用透明大页(THP)

问题详情

我在/dev/shm目录下有一个任意大小的只读文件(大小不一定是2MB的倍数,最小可至120KB),尝试通过shm_open+mmap将其映射到内存,再调用带MADV_HUGEPAGE参数的madvise来启用透明大页(THP),但始终无法生效。

已做配置

echo advise >/sys/kernel/mm/transparent_hugepage/shmem_enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/sysconf.h>
#include <sys/shm.h>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <file_path>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    const char *file_path = argv[1];
    int fd = shm_open(file_path, O_RDONLY, 0666);
    if (fd == -1) {
        perror("shm_open");
        exit(EXIT_FAILURE);
    }

    struct stat sb;
    if (fstat(fd, &sb) == -1) {
        perror("fstat");
        close(fd);
        exit(EXIT_FAILURE);
    }

    size_t huge_page_size = sysconf(_SC_HUGEPAGESIZE);
    if (huge_page_size == -1) {
        perror("sysconf");
        close(fd);
        exit(EXIT_FAILURE);
    }

    void *addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
    if (addr == MAP_FAILED) {
        perror("mmap");
        close(fd);
        exit(EXIT_FAILURE);
    }

    if (madvise(addr, sb.st_size, MADV_HUGEPAGE) == -1) {
        perror("madvise");
        munmap(addr, sb.st_size);
        close(fd);
        exit(EXIT_FAILURE);
    }

    // TODO: do something for 10 mins or more
    // ... Read the file and do something.
    // After 10 mins or more.

    munmap(addr, sb.st_size);
    close(fd);

    return 0;
}

复现步骤

  • 在/dev/shm创建任意大小的文件;
  • 运行上述代码并传入文件路径;
  • 查看/proc/meminfo中的ShmemHugePages值,始终为0。

系统信息

  • Linux内核:5.4
  • 架构:x86_64

补充说明

  • 文件为只读模式,大小不固定;
  • 已配置shmem的THP策略为advise。

解决方法

1. 修正全局THP配置

你当前设置transparent_hugepage/enabled=never会全局禁用所有THP功能,直接覆盖了shmem_enabled的配置。必须将其改为madvise,这样内核才会响应MADV_HUGEPAGE的建议:

echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo advise >/sys/kernel/mm/transparent_hugepage/shmem_enabled

2. 触发页面实际访问

THP不会在映射完成后立即分配,只有当页面被实际读取/写入时,内核才会尝试将普通页合并为大页。你需要在madvise之后,主动遍历映射区域触发页面加载:

// 替换原代码中的TODO部分
char *ptr = (char *)addr;
size_t huge_page_size = sysconf(_SC_HUGEPAGESIZE);

// 遍历每个大页起始位置,触发页面加载(volatile避免编译器优化)
for (size_t i = 0; i < sb.st_size; i += huge_page_size) {
    volatile char dummy = ptr[i];
}

// 保持进程运行,方便验证
sleep(600);

3. 优化映射对齐(可选)

如果希望尽可能多的区域使用大页,可以将映射大小向上对齐到最近的大页尺寸。不过这不是强制要求,内核会自动处理非对齐部分的普通页:

// 计算对齐后的大小
size_t aligned_size = ((sb.st_size + huge_page_size - 1) / huge_page_size) * huge_page_size;
// 使用对齐后的大小进行映射
void *addr = mmap(NULL, aligned_size, PROT_READ, MAP_SHARED, fd, 0);

4. 验证方法

除了查看/proc/meminfo,还可以通过以下方式确认THP是否生效:

  • 查看进程的/proc/<pid>/smaps,查找包含ShmemHugePages的行,查看大页占用量;
  • 使用grep AnonHugePages /proc/<pid>/status查看进程的大页使用情况。

内容的提问来源于stack exchange,提问作者Tefone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 19:41:08