WinAPI VirtualQueryEx统计进程内存与任务管理器数值不符问题
进程内存统计差异:自定义WinAPI函数与任务管理器数值不符的原因
你的代码逻辑存在两处关键问题,同时你统计的内存指标和任务管理器的统计口径完全不同,两者共同导致了数值差异。
一、代码逻辑的错误
32位地址截断问题
你用DWORD类型存储内存地址(currAddr和mbi.BaseAddress的强制转换),在64位系统下,64位内存地址会被截断为32位,这会导致遍历内存区域时出现地址错误,要么漏统计大量内存区域,要么错误触发重复地址判断提前终止循环。正确的做法是用LPVOID或UINT_PTR/SIZE_T来存储地址,避免截断。多余的重复地址判断
VirtualQueryEx本身是按进程虚拟地址空间的顺序遍历内存区域的,绝不会返回重复的基地址。你添加的tempAddresses完全多余,反而会因为地址截断问题错误判定地址重复,导致循环提前终止,统计不完整。
二、统计口径的差异
任务管理器“详细信息”页显示的“内存”默认是专用工作集(Private Working Set):
- 这部分是进程独占的、已经加载到物理内存中的内存,不包含共享内存,也不包含已经提交但尚未被访问(仍在虚拟内存分页文件中)的私有内存。
而你的代码统计的是所有提交的私有虚拟内存(MEM_COMMIT + MEM_PRIVATE):
- 这包括了所有进程已经向系统申请并提交的私有虚拟内存,不管是否已经被加载到物理内存,范围比专用工作集大得多,数值自然更高。
修正方案
1. 修正后的提交私有内存统计代码
如果你的需求确实是统计所有提交的私有虚拟内存,修正地址处理和去掉多余判断后的代码如下:
#include <Windows.h> SIZE_T GetProcessCommitedMemorySize(const HANDLE hProcess) { MEMORY_BASIC_INFORMATION mbi; SIZE_T totalMemory = 0; LPVOID currAddr = nullptr; while (VirtualQueryEx(hProcess, currAddr, &mbi, sizeof(mbi)) == sizeof(mbi)) { // 移动到下一个内存区域 currAddr = reinterpret_cast<LPVOID>( reinterpret_cast<UINT_PTR>(mbi.BaseAddress) + mbi.RegionSize ); if (mbi.State == MEM_COMMIT && mbi.Type == MEM_PRIVATE) { totalMemory += mbi.RegionSize; } } return totalMemory; }
2. 匹配任务管理器数值的代码
如果要和任务管理器显示的内存数值对齐,应该使用GetProcessMemoryInfo函数获取专用工作集大小,这个接口直接返回系统统计的进程内存指标,无需手动遍历:
#include <Windows.h> #include <psapi.h> #pragma comment(lib, "psapi.lib") SIZE_T GetProcessPrivateWorkingSet(const HANDLE hProcess) { PROCESS_MEMORY_COUNTERS_EX pmc; if (GetProcessMemoryInfo(hProcess, reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc), sizeof(pmc))) { // PrivateUsage就是专用工作集大小,和任务管理器显示的数值一致 return pmc.PrivateUsage; } return 0; }
内容的提问来源于stack exchange,提问作者Noam Patai
相关产品推荐
相关产品推荐

