导读:本期聚焦于小伙伴创作的《C++如何获取系统的物理内存占用峰值?用GetProcessMemoryInfo实战讲解》,敬请观看详情。想知道自己写的C++程序在运行期间最高吃掉多少物理内存,光看任务管理器不够精确。Windows提供了GetProcessMemoryInfo接口,其中的PeakWorkingSetSize字段直接记录了进程工作集的物理内存峰值。本文实战演示如何调用Psapi.h里的该函数,配合PROCESS_MEMORY_COUNTERS_EX结构拿到数据。不少同学分不清工作集和私有内存的区别,误把PagefileUsage当成物理占用,结果统计偏差很大。下面通过完整代码示例展示句柄获取、结构填充与数值转换,并说明x86与x64下字段长度差异带来的注意事项,帮你准确监控程序内存水位。

在Windows平台做C++性能分析时,准确掌握进程的物理内存占用峰值对排查内存泄漏和评估资源消耗非常关键。系统为每个进程维护了一份内存计数器,其中物理内存相关的峰值数据可以通过PSAPI中的GetProcessMemoryInfo函数读取。

C++如何获取系统的物理内存占用峰值?用GetProcessMemoryInfo实战讲解

一、核心API与数据结构解析

GetProcessMemoryInfo定义在Psapi.h中,需要链接Psapi.lib。该函数接收进程句柄、指向内存计数器结构的指针以及结构大小,将当前进程的内存统计信息填入结构中。我们通常使用扩展结构PROCESS_MEMORY_COUNTERS_EX,它兼容基础结构并在末尾增加了一些字段。

结构中的PeakWorkingSetSize成员以字节为单位,表示进程自启动以来工作集(即驻留物理内存)的最高值。工作集就是操作系统真正放在物理内存里供进程使用的页面集合,因此它直接反映物理内存占用峰值。与之容易混淆的PeakPagefileUsage记录的是页文件提交峰值,属于虚拟内存范畴,并非物理占用。

1.1 关键字段说明

除了PeakWorkingSetSize,结构中还有WorkingSetSize(当前工作集)、QuotaPagedPoolUsage(分页池配额)等。实战中我们重点关注峰值字段,因为它能告诉我们程序在压力最大时消耗了多少物理资源。

在x64系统上,这些Size字段是SIZE_T类型,宽度随平台变化。用%llu打印SIZE_T时,建议在32位下做强制转换,避免格式符不匹配导致输出异常。

二、实战代码演示

下面给出一个完整的控制台程序,演示如何获取并打印当前进程的physical memory peak。代码以文本形式展示,所有小于号和大于号均已转义。

#include <windows.h>
#include <psapi.h>
#include <stdio.h>

#pragma comment(lib, "psapi.lib")

int main() {
    HANDLE hProcess = GetCurrentProcess();
    PROCESS_MEMORY_COUNTERS_EX pmc;
    pmc.cb = sizeof(pmc);

    if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) {
        SIZE_T peakWS = pmc.PeakWorkingSetSize;
        printf("Physical memory peak (bytes): %llun", (unsigned long long)peakWS);
        printf("Physical memory peak (MB): %llun", (unsigned long long)(peakWS / (1024 * 1024)));
    } else {
        printf("GetProcessMemoryInfo failed, error: %lun", GetLastError());
    }

    return 0;
}

上述代码首先通过GetCurrentProcess获取进程句柄,该句柄无需关闭。然后将cb字段设为结构大小,这是Windows API常见的版本控制方式。调用成功后,PeakWorkingSetSize即所需峰值。

若需要监控其他进程,应使用OpenProcess请求PROCESS_QUERY_INFORMATION权限,并在使用后CloseHandle。对系统服务或保护进程可能无权打开,需做好错误处理。

2.1 监控外部进程示例

以下片段展示如何附加到指定PID并读取其峰值。注意权限不足时会返回NULL句柄。

#include <windows.h>
#include <psapi.h>
#include <stdio.h>

#pragma comment(lib, "psapi.lib")

void print_peak(DWORD pid) {
    HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
    if (!h) {
        printf("open fail %lun", GetLastError());
        return;
    }
    PROCESS_MEMORY_COUNTERS_EX pmc;
    pmc.cb = sizeof(pmc);
    if (GetProcessMemoryInfo(h, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) {
        printf("pid %lu peak MB: %llun", pid, (unsigned long long)(pmc.PeakWorkingSetSize / (1024*1024)));
    }
    CloseHandle(h);
}

三、常见误区与注意点

一个典型误区是把PrivateUsage或PagefileUsage当作物理内存峰值。PrivateUsage反映进程独占的提交内存,可能很大一部分还在页文件或待分配状态,并不能说明物理占用。只有WorkingSet系列才和物理内存直接相关。

另一个注意点是峰值只增不减。系统记录的是历史最高,因此若想测量某段逻辑的内存高峰,应重启进程或在该逻辑前记录初始值,用当前峰值减去基线做区间评估,否则会包含启动期加载的库内存。

3.1 多平台差异

本文方法仅适用于Windows。Linux下应读取/proc/self/status中的VmHWM字段,macOS则用task_info的phys_footprint。跨平台项目建议封装统一接口,根据宏区分实现。

此外,在WSL或容器环境里,GetProcessMemoryInfo看到的是宿主视角的占用,可能和cgroup限制不一致,需要结合其他手段做资源约束分析。

四、小结

通过GetProcessMemoryInfo配合PROCESS_MEMORY_COUNTERS_EX,C++开发者能以极低开销拿到准确的物理内存占用峰值。核心就是读取PeakWorkingSetSize,并理解它和虚拟内存指标的区别。实战中注意句柄权限、字段类型与峰值单调性,就能把这套逻辑稳稳嵌入性能监控模块。

当你需要长期采样时,可起一个独立线程周期性调用该函数,将峰值上报到日志或监控面板,以及时发现内存水位异常上涨的趋势。

C++GetProcessMemoryInfophysical_memory_peak修改时间:2026-08-06 05:18:28

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。