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

使用MAP_ANONYMOUS的mmap(),如何查看实际分配的物理页数?

确认MAP_ANONYMOUS mmap实际分配的物理页数

好问题!你对MAP_ANONYMOUS标志的mmap()行为理解得很到位——这种方式分配的虚拟内存一开始只是零填充的虚拟页,基于写时复制(COW)和请求分页机制,只有当你实际对某页执行写入(甚至部分读取操作,但匿名初始零页的读取通常不会触发分配)时,内核才会为该页分配真正的物理内存。

下面是几种可靠的方法来验证实际分配的物理页数:

1. 用pmap命令直观查看进程内存细节

这是最方便的离线验证方法,步骤如下:

  • 先运行你的程序,获取它的进程ID(PID),可以用ps aux | grep 你的程序名,或者在程序里通过getpid()打印PID。
  • 执行pmap -x <PID>,输出会按内存区域拆分详细信息,重点看这几个字段:
    • RSS:该区域实际驻留在物理内存中的大小(单位KB)
    • Dirty:被修改过的内存大小(也就是触发了COW分配物理页的部分)
  • 找到你用MAP_ANONYMOUS分配的内存区域,用RSS值除以系统页大小(通常是4KB),就能得到实际分配的物理页数。比如如果RSS是4KB,说明只有1页被分配了物理内存,和你只写入中间一页的预期完全一致。

2. 在程序内部读取proc文件系统

如果你想在程序运行时自行检查,可以读取Linux的proc文件系统:

  • 全局统计:读取/proc/self/status,里面的VmRSS字段是进程整体使用的物理内存大小(单位KB),对比写入前后的数值变化,差值就是你的匿名页触发的物理内存分配量。
  • 精确到内存区域:读取/proc/self/smaps,这个文件会按每个内存区域拆分信息,找到你映射的虚拟地址范围对应的条目,看Rss和Dirty字段,直接对应该区域的物理内存使用情况。你可以在程序里打开这个文件,逐行匹配地址范围来提取数据。

3. 使用mincore()系统调用直接查询页驻留状态

mincore()是专门用来查询虚拟页是否驻留在物理内存中的系统调用,它会返回一个字节数组,每个字节的最低位表示对应页是否在内存中。

给你一个C语言的示例代码:

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main() {
    size_t map_size = 10 * 1024 * 1024; // 分配10MB匿名内存
    int page_size = getpagesize();
    size_t num_pages = map_size / page_size;

    // 执行匿名内存映射
    void *addr = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (addr == MAP_FAILED) {
        perror("mmap failed");
        exit(EXIT_FAILURE);
    }

    // 写入中间的一页(触发COW分配物理页)
    size_t middle_page_idx = num_pages / 2;
    memset((char*)addr + middle_page_idx * page_size, 0xAA, 1);

    // 准备mincore的结果缓冲区
    unsigned char *vec = malloc(num_pages);
    if (!vec) {
        perror("malloc failed");
        munmap(addr, map_size);
        exit(EXIT_FAILURE);
    }

    // 查询页驻留状态
    if (mincore(addr, map_size, vec) == -1) {
        perror("mincore failed");
        free(vec);
        munmap(addr, map_size);
        exit(EXIT_FAILURE);
    }

    // 统计驻留物理页数
    int resident_count = 0;
    for (size_t i = 0; i < num_pages; i++) {
        if (vec[i] & 1) {
            resident_count++;
        }
    }

    printf("实际分配的物理页数: %d\n", resident_count);

    // 清理资源
    free(vec);
    munmap(addr, map_size);
    return EXIT_SUCCESS;
}

编译运行后,你会发现输出的驻留页数是1,完全符合只写入一页的预期。

4. 用perf跟踪缺页错误事件

当虚拟页没有对应物理页时,会触发缺页错误,其中写缺页错误会触发COW分配物理页。你可以用perf工具统计这些事件:

  • 运行perf record -e page-faults,minor-faults ./你的程序
  • 执行perf report查看结果,minor-faults的数量应该等于你写入的页数(匿名页的缺页属于minor fault,不需要从磁盘加载数据)。

这种方法可以帮你验证程序运行过程中到底触发了多少次物理页分配。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:01:28