VMMap与任务管理器内存显示差异及技术疑问
Windows内存实验:Committed Size vs Working Set 差异验证
为验证Committed Size可能小于Working Set,我开展了如下实验:
实验步骤
1. 编译大体积DLL并复制为多份
编写包含大常量数据段的DLL项目,编译后重命名为5个不同的DLL文件,代码如下:
// LargeDLL.cpp #include <windows.h> const BYTE g_largeData[50 * 1024 * 1024] = { 0 }; extern "C" __declspec(dllexport) void DummyFunction() { volatile int dummy = g_largeData[0]; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; }
2. 编写加载多DLL的测试程序
编写程序循环加载上述5个DLL,并调用导出函数触发数据段访问,代码如下:
// TestDLLLoad.cpp #include <windows.h> #include <iostream> #include <vector> typedef void (*DummyFunc)(); int main() { std::vector<HMODULE> loadedDLLs; const char* dllNames[] = { "LargeDLL_A.dll", "LargeDLL_B.dll", "LargeDLL_C.dll", "LargeDLL_D.dll", "LargeDLL_E.dll" }; for (const char* dllName : dllNames) { HMODULE hDLL = LoadLibraryA(dllName); if (hDLL == NULL) { std::cerr << "Failed to load " << dllName << ", error: " << GetLastError() << std::endl; return 1; } loadedDLLs.push_back(hDLL); DummyFunc func = (DummyFunc)GetProcAddress(hDLL, "DummyFunction"); if (func) { func(); } } std::cout << "All DLLs loaded. Check Task Manager now. Press Enter to exit..." << std::endl; std::cin.get(); for (auto hDLL : loadedDLLs) { FreeLibrary(hDLL); } return 0; }
实验结果
VMMap 内存统计
[Type] [Committed] [Private] [Total Working Set] [Private Working Set] [Shareable Working Set] Total 321,124K 1,612K 5,380K 1,180K 4,200K Heap 196K 132K 136K 132K 4K Image 318,584K 636K 4,088K 228K 3,860K MappedFile 1,260K 0K 124K 0K 124K PageTable 780K 780K 780K 780K 0K PrivateData 32K 32K 28K 20K 8K Sharable 240K 0K 204K 0K 204K Stack 32K 32K 20K 20K 0K
任务管理器内存统计
Working Set (memory): 4,632K Private Working Set (memory): 432K Sharable Working Set (memory): 4,200K Commit Size: 1,644K
技术疑问与解答
疑问1:VMMap与任务管理器的Private Working Set、总Working Set数值差异原因
VMMap的Private Working Set包含进程的页表(PageTable)内存,而任务管理器的Private Working Set会排除页表。除此之外,VMMap的统计还包含内核模式下为进程分配的私有辅助结构,这些内容不会被任务管理器归类到进程私有内存中;任务管理器仅统计用户模式下的私有可写内存、私有堆、栈等。
总Working Set的差异源于VMMap的Total Working Set是所有类型内存的Working Set总和,包含部分任务管理器不统计的内核关联内存项;而任务管理器的Working Set仅计算Private Working Set与Sharable Working Set的和,因此两者数值不同。
疑问2:VMMap与任务管理器的Commit Size数值差异原因
VMMap的Committed统计的是进程地址空间中所有标记为已提交的内存范围,包括:
- DLL整个镜像文件的大小(包括未被访问的50MB零初始化数据段,Windows会标记为已提交但延迟加载);
- 页表、映射文件的已提交部分等。
而任务管理器的Commit Size仅统计进程实际消耗的、无法与其他进程共享的提交内存:
- DLL的只读/可执行段是共享的,不计入进程Commit Size;
- 零初始化数据段未被访问时,Windows不会分配物理页,也不计入Commit Size;仅被访问的部分(每个DLL仅触发1个4KB页)会被统计;
- 仅包含进程私有堆、栈、私有数据页等非共享提交内存。
你的5个DLL仅触发了5个4KB私有数据页提交,加上进程自身的堆、栈等开销,总和接近1644K;而VMMap统计了所有DLL的镜像大小,因此出现321124K的大数值。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

