如何整合PROCESS_MEMORY_COUNTERS_EX结构体返回的进程内存信息?
嘿,这个问题我之前做Windows进程监控的时候也碰到过——PROCESS_MEMORY_COUNTERS_EX确实把内存数据拆得很细碎,不过只要按照内存的不同属性归类,再做些格式化转换,就能把这些零散的数据变成清晰有用的信息。下面我分享几个实用的处理思路和代码示例:
1. 按内存类型归类整理
先把结构体里的字段按内存维度分组,这样能快速理清不同类别的内存占用情况:
- 工作集内存(Working Set):进程当前实际加载到物理内存中的部分,包含共享和私有内容
PeakWorkingSetSize:工作集内存的历史峰值WorkingSetSize:当前工作集内存大小
- 系统内核池内存:进程向系统内核申请的内存资源
- 分页池:
QuotaPeakPagedPoolUsage(峰值)、QuotaPagedPoolUsage(当前)——可被交换到页文件的内核内存 - 非分页池:
QuotaPeakNonPagedPoolUsage(峰值)、QuotaNonPagedPoolUsage(当前)——必须留在物理内存的内核内存
- 分页池:
- 虚拟/私有内存:进程独占的虚拟内存空间(包括物理内存和页文件中的部分)
PagefileUsage:当前进程占用的页文件大小PeakPagefileUsage:页文件使用的历史峰值PrivateUsage:进程独占的内存大小(这是日常排查内存泄漏时最常用的指标之一)
2. 把字节数转换成易读的单位
结构体返回的所有SIZE_T字段都是字节数,直接看数字太不直观,写个小工具函数把字节转换成带单位的字符串:
#include <string> #include <cmath> #include <cstdio> std::string FormatMemorySize(SIZE_T bytes) { const char* units[] = {"B", "KB", "MB", "GB", "TB"}; int unitIndex = 0; double size = static_cast<double>(bytes); // 按1024进制转换单位 while (size >= 1024 && unitIndex < 4) { size /= 1024; unitIndex++; } char buffer[64]; snprintf(buffer, sizeof(buffer), "%.2f %s", size, units[unitIndex]); return std::string(buffer); }
调用这个函数,比如FormatMemorySize(pmce.PrivateUsage),就能得到类似"185.60 MB"的友好结果。
3. 封装成可复用的工具函数/结构体
把获取和处理的逻辑封装起来,以后需要获取进程内存信息时直接调用就行,不用重复写代码:
#include <windows.h> #include <psapi.h> #include <string> // 链接PSAPI库,VS环境下可以加这个编译指令 #pragma comment(lib, "psapi.lib") // 整理后的内存信息结构体 struct ProcessMemoryStats { std::string workingSetCurrent; std::string workingSetPeak; std::string pagedPoolCurrent; std::string pagedPoolPeak; std::string nonPagedPoolCurrent; std::string nonPagedPoolPeak; std::string pagefileCurrent; std::string pagefilePeak; std::string privateUsage; }; ProcessMemoryStats GetProcessMemoryStats(DWORD processId) { ProcessMemoryStats stats; // 打开进程,需要查询信息和读取内存的权限 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); if (!hProcess) { return stats; } PROCESS_MEMORY_COUNTERS_EX pmce; pmce.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX); if (GetProcessMemoryInfo(hProcess, reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmce), pmce.cb)) { // 把每个字段转换成易读的格式 stats.workingSetCurrent = FormatMemorySize(pmce.WorkingSetSize); stats.workingSetPeak = FormatMemorySize(pmce.PeakWorkingSetSize); stats.pagedPoolCurrent = FormatMemorySize(pmce.QuotaPagedPoolUsage); stats.pagedPoolPeak = FormatMemorySize(pmce.QuotaPeakPagedPoolUsage); stats.nonPagedPoolCurrent = FormatMemorySize(pmce.QuotaNonPagedPoolUsage); stats.nonPagedPoolPeak = FormatMemorySize(pmce.QuotaPeakNonPagedPoolUsage); stats.pagefileCurrent = FormatMemorySize(pmce.PagefileUsage); stats.pagefilePeak = FormatMemorySize(pmce.PeakPagefileUsage); stats.privateUsage = FormatMemorySize(pmce.PrivateUsage); } CloseHandle(hProcess); return stats; }
比如要获取当前进程的内存信息,直接调用GetProcessMemoryStats(GetCurrentProcessId())就行。
4. 格式化输出,让数据一目了然
拿到整理后的信息后,可以输出成清晰的格式,比如在控制台打印:
void PrintProcessMemoryStats(const ProcessMemoryStats& stats) { printf("=== 进程内存统计信息 ===\n"); printf("工作集内存:当前 %s | 峰值 %s\n", stats.workingSetCurrent.c_str(), stats.workingSetPeak.c_str()); printf("分页池内存:当前 %s | 峰值 %s\n", stats.pagedPoolCurrent.c_str(), stats.pagedPoolPeak.c_str()); printf("非分页池内存:当前 %s | 峰值 %s\n", stats.nonPagedPoolCurrent.c_str(), stats.nonPagedPoolPeak.c_str()); printf("页文件使用:当前 %s | 峰值 %s\n", stats.pagefileCurrent.c_str(), stats.pagefilePeak.c_str()); printf("私有内存:%s\n", stats.privateUsage.c_str()); }
输出的结果会非常直观:
=== 进程内存统计信息 === 工作集内存:当前 128.50 MB | 峰值 156.20 MB 分页池内存:当前 2.30 MB | 峰值 2.50 MB 非分页池内存:当前 1.10 MB | 峰值 1.20 MB 页文件使用:当前 200.40 MB | 峰值 220.10 MB 私有内存:180.30 MB
最后提个小注意点:调用OpenProcess时需要确保有足够的权限,如果是获取系统进程的内存信息,可能需要以管理员身份运行程序。
内容的提问来源于stack exchange,提问作者user7847018
相关产品推荐
相关产品推荐

