当前内存使用显示总是比任务管理器多 ~14MB

Current memory usage display is always ~14MB more than task manager

我目前正在使用 this answer 中的代码,并按照评论中的建议进行了一些细微的修改。但是,无论我在内存中分配多少对象,列出的内存使用量总是比任务管理器列出的多 ~14MB。为什么会这样?

std::stringstream ss;

PROCESS_MEMORY_COUNTERS_EX pmc;
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
SIZE_T physMemUsedByMe = pmc.WorkingSetSize;

ss << "\nMEM: " << (physMemUsedByMe / 1024 / 1024) << " MB";    

debugText.setString(ss.str());

正常构建的结果:

调试文本:

任务管理器:

资源监视器:

分配 10,000 个虚拟对象时的结果:

调试文本:

任务管理器:

资源监视器:

编辑:

按照评论建议使用资源监视器 (perfmon) 后,我发现 Working Set 的列与我正在使用的内存列表功能相匹配。但是,我仍然对为什么 Working Set 列和 Private 列之间存在 ~14MB 的差异感到困惑(后者是任务管理器似乎使用的)。为什么会这样?

任务管理器不使用 Win32 API GetProcessMemoryInfo() 功能。它使用 NT API ZwQueryInformationProcess() 函数,将 ProcessInformationClass 参数设置为 ProcessVmCounters.

从Windows10开始,定义如下结构(在ntddk.h):

typedef struct _VM_COUNTERS_EX2 {
    VM_COUNTERS_EX CountersEx;
    SIZE_T PrivateWorkingSetSize;
    ULONGLONG SharedCommitUsage;
} VM_COUNTERS_EX2, *PVM_COUNTERS_EX2;

任务管理器使用VM_COUNTERS_EX2类似于下面的代码:

VM_COUNTERS_EX2 vm;
ZwQueryInformationProcess(hProcess, ProcessVmCounters, &vm, sizeof(vm), 0);

它为 "Memory(private working set)" 列显示的值是 vm.PrivateWorkingSetSize 字段。

看起来目前不存在 Win32 API 模拟。如何查看:

typedef struct _VM_COUNTERS_EX {
    SIZE_T PeakVirtualSize;
    SIZE_T VirtualSize;// note this !!
    ULONG PageFaultCount;
    SIZE_T PeakWorkingSetSize;
    SIZE_T WorkingSetSize;
    SIZE_T QuotaPeakPagedPoolUsage;
    SIZE_T QuotaPagedPoolUsage;
    SIZE_T QuotaPeakNonPagedPoolUsage;
    SIZE_T QuotaNonPagedPoolUsage;
    SIZE_T PagefileUsage;
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivateUsage;
} VM_COUNTERS_EX;

VM_COUNTERS_EX2VM_COUNTERS_EX 基数非常接近 PROCESS_MEMORY_COUNTERS_EX 但不精确(没有 [Peak]VirtualSize)成员)。 GetProcessMemoryInfo() 内部调用 ZwQueryInformationProcess(hProcess, ProcessVmCounters),然后将 VM_COUNTERS_EX 复制到 PROCESS_MEMORY_COUNTERS_EX


在 Windows 10 的任务管理器中,"Memory(physical memory reserved by individual processes)" 列显示 PrivateWorkingSet(以 1024 字节为增量)。 "Details" 选项卡(私有工作集)下显示了相同的值。由于未知原因,该值以 1000 字节为增量显示,因此实际值始终高出 1.024 倍。

但是您使用 "total" 工作集 - WorkingSetSize - 这是 "private" 和 "shared" 工作集的总和(您需要将列添加到详细信息选项卡查看此内容,默认情况下仅显示私有内存)。因此,结果存在恒定差异 (14 MB) - 这是 "shared" 工作集(通常是常见的 DLL,如 ntdll.dllkerner32.dllkernelbase.dll 等).当您分配内存(10,000 个虚拟对象)时,这种差异不会改变。 "private" 工作集增长,但 "shared" 工作集保持不变(因为没有新的 DLL loaded/unloaded)。

如果您想像任务管理器那样显示内存,请使用来自 NT API 的 VM_COUNTERS_EX2PrivateWorkingSetSize 成员。如果您不能使用它,那么您将得到与任务管理器不同的结果。

如果你不喜欢 NT API,或者不理解它,这不是我的问题(或者也许有人可以 现在 得到 PrivateWorkingSetSize 通过使用一些 "documented" API?)。如果任务管理器使用NTAPI,这也不是我的选择