商城首页欢迎来到中国正版软件门户

您的位置:首页 >C++如何获取当前进程的虚拟内存大小 _ 平台特定API调用方法【实战】

C++如何获取当前进程的虚拟内存大小 _ 平台特定API调用方法【实战】

  发布于2026-05-05 阅读(0)

扫一扫,手机访问

C++如何获取当前进程的虚拟内存大小:平台特定API调用方法【实战】

在Linux下,读取/proc/self/statm是获取虚拟内存大小最直接的方法。其第一列表示总虚拟内存页数,乘以sysconf(_SC_PAGESIZE)得到的字节数,就对应着top命令中的VIRT值。这个数值包含了代码、数据、栈、共享库以及所有mmap映射区域在内的全部虚拟地址空间。

C++如何获取当前进程的虚拟内存大小 _ 平台特定API调用方法【实战】

Linux下用/proc/self/statm读取虚拟内存大小

想在Linux上获取进程的虚拟内存大小?最直接、最经典的路径就是解析/proc/self/statm这个伪文件。它的第一列,也就是size字段,直接给出了进程占用的总虚拟内存页数。你只需要将这个数字乘以系统的页大小,就能得到以字节为单位的VIRT值——没错,就是tophtop命令里VIRT那一列显示的数字。

听起来简单,但实操起来有几个细节必须把握:

立即学习“C++免费学习笔记(深入)”;

  • 获取页大小要动态:务必使用sysconf(_SC_PAGESIZE)来获取系统页大小,可别想当然地硬编码4096。要知道,在一些ARM或RISC-V架构的系统上,页大小可能不同。
  • 字段固定,读取直接/proc/self/statm每行固定有7个由空格分隔的字段,第一列就是我们要的size。它统计的是整个程序映像的大小,囊括了代码段、数据段、堆栈、共享库以及所有通过mmap映射的区域。
  • 注意读取频率:虽然这个文件由内核动态生成,没有磁盘I/O开销,但每次读取依然是一次系统调用。对于需要高频监控的场景,建议将频率控制在每秒1到2次以内,避免不必要的性能损耗。
  • 核心代码片段
    long page_size = sysconf(_SC_PAGESIZE);
    std::ifstream f(“/proc/self/statm”);
    long size_in_pages;
    f >> size_in_pages;
    size_t virt_bytes = static_cast(size_in_pages) * page_size;

macOS用task_info获取virtual_size

到了macOS,事情就变得不一样了。这里没有/proc文件系统,必须通过Mach微内核的API来获取信息。核心在于调用task_info函数,并传入TASK_BASIC_INFO_64这个信息 fla vor。返回的结构体中,virtual_size字段就是我们需要的虚拟内存字节数(切记,不是resident_size)。

这个过程有几个关键点容易踩坑:

立即学习“C++免费学习笔记(深入)”;

  • 头文件与链接:需要包含。链接时,通常需要-framework CoreServices。在实际操作中,尤其是使用Xcode时,显式添加-framework Foundation可以避免一些潜在的符号冲突。
  • 错误检查不可少:返回值类型是kern_return_tKERN_SUCCESS。常见的错误KERN_INVALID_ARGUMENT,很多时候是因为task_for_pid的权限被拒绝——这在macOS 10.15 (Catalina) 及之后的版本中尤为常见,系统默认会拒绝非root进程的调试权限。
  • 确保使用64位结构体:务必使用TASK_BASIC_INFO_64_COUNT宏作为count参数传入。如果误用了32位结构体的计数,在64位进程下会导致越界读取,引发不可预知的问题。
  • 示例关键代码
    struct task_basic_info_64 tinfo;
    mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
    kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO_64,
                                  (task_info_t)&tinfo, &count);
    if (kr == KERN_SUCCESS) {
        size_t virt_bytes = tinfo.virtual_size;
    }

Windows用GetProcessMemoryInfo的PagefileUsage

Windows平台并没有一个与Linux VIRT完全对等的概念。最接近的指标是使用GetProcessMemoryInfo函数获取PROCESS_MEMORY_COUNTERS_EX结构体,其中的PagefileUsage成员。它表示进程当前承诺使用的页面文件空间总量,包含了已提交(committed)但可能尚未被使用的虚拟地址空间,其语义与top的VIRT大致相当。

在Windows上实现时,需要特别注意以下几点:

立即学习“C++免费学习笔记(深入)”;

  • 使用正确的结构体:必须使用扩展版本PROCESS_MEMORY_COUNTERS_EX,因为基础的PROCESS_MEMORY_COUNTERS结构体不包含PagefileUsage字段。
  • 权限问题:调用前,有时需要启用SE_DEBUG_NAME权限。对于查询自身进程信息的情况,通常可以跳过。但如果你的进程运行在沙盒或低完整性级别下,可能仍然需要调用OpenProcessTokenAdjustTokenPrivileges来调整权限。
  • 理解统计范围PagefileUsage的单位直接就是字节,无需转换。但必须清楚它的统计范围:它只包含已提交(COMMIT)的内存,而不包括那些仅保留(RESERVE)而未提交的地址空间(通过VirtualAlloc with MEM_RESERVE分配的部分)。这一点与Linux的/proc/self/statm不同,后者会统计保留区域。
  • 代码示例简写
    PROCESS_MEMORY_COUNTERS_EX pmc;
    pmc.cb = sizeof(pmc);
    if (GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc))) {
        size_t virt_bytes = pmc.PagefileUsage;
    }

跨平台封装要注意的三个断裂点

把各个平台的代码写出来只是第一步。当试图将它们封装成一个统一的跨平台接口时,才会遇到真正的挑战。表面上看只是“读取一个数字”,但底层语义的差异极易导致封装结果失真。以下是三个最容易被忽略的“断裂点”:

  • 统计范围的本质差异:Linux /proc/self/statmsize包含了所有mmap映射的区域(无论是匿名的还是共享的)。而Windows的PagefileUsage只计算已提交的部分。如果你的程序大量使用了mmap并设置了MAP_NORESERVE标志,那么在Linux和Windows上报告出来的“虚拟内存大小”可能会相差数GB之多。
  • macOS的特殊性:macOS的virtual_size虽然包含了所有的vm_map_entry,但会自动排除一些内核的私有映射,例如动态链接器共享缓存(dyld shared cache)的只读部分。实际测试中,同一个程序在macOS上报告的值可能比在Linux上低10到20MB。
  • 用户态视角的局限:所有平台通过用户态API获取的数值,都不包含内核态为进程分配的内存。例如,驱动程序分配的DMA缓冲区、网络栈为Socket预留的接收队列等,这些资源虽然被进程使用,但不会体现在上述API的返回值中。如果你的监控目标是评估“进程的总资源占用”,就必须借助更底层的工具,例如解析Linux的/proc/[pid]/maps或使用macOS的vmmap命令进行辅助分析。
本文转载于:https://www.php.cn/faq/2420188.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注