【问题标题】:Current memory usage display is always ~14MB more than task manager当前内存使用情况显示总是比任务管理器多约 14MB
【发布时间】:2017-08-16 14:35:30
【问题描述】:

我目前正在使用this answer 中的代码,并按照 cmets 中的建议进行了一些细微的修改。但是,无论我在内存中分配了多少对象,列出的内存使用量总是比任务管理器列出的多约 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 个虚拟对象时的结果:

调试文本:

任务管理器:

资源监视器:

编辑:

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

【问题讨论】:

  • 发布可编译代码。
  • 任务管理器提供许多不同的内存测量。请指定您要引用的内容(提供完整的列标题)。
  • 这仅在 windows 10 下?尝试使用 VM_COUNTERS_EX2.PrivateWorkingSetSize 并与来自 taskmgr 的数据进行比较。但是在 win 8.1 和早期版本中,您的代码必须显示与 taskmgr 相同的结果
  • 不要将任务管理器用作调试工具,它不是为此而设计的。它以并不总是显而易见的方式处理共享和分页的记忆。如果必须,请使用 perfmon。
  • 共享 DLLS 不会被加载到每个进程空间中。它们被映射进去。这就是您所看到的差异。

标签: c++ windows winapi memory taskmanager


【解决方案1】:

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

从 Windows 10 开始,定义了以下结构(在 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);

它为“内存(私有工作集)”列显示的值是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 的任务管理器中,“内存(单个进程保留的物理内存)”列显示 PrivateWorkingSet(以 1024 字节为增量)。同样的值显示在“详细信息”选项卡(私有工作集)下。由于未知原因,该值以 1000 字节为增量显示,因此实际值始终高出 1.024 倍。

但是您使用“总”工作集 - WorkingSetSize - 这是“私有”和“共享”工作集的总和(您需要在“详细信息”选项卡中添加列才能查看此内容,默认情况下只有私人内存显示)。所以,结果有一个恒定的差异(14 MB) - 这是“共享”工作集(通常是常见的 DLL,如ntdll.dllkerner32.dllkernelbase.dll 等)。当您分配内存(10,000 个虚拟对象)时,这种差异不会改变。 “私有”工作集增长,但“共享”工作集保持不变(因为没有加载/卸载新的 DLL)。

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

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

【讨论】:

  • 我并不是要粗鲁,但我不明白你在说什么你的答案的结构。
  • @TrampolineTales - 我试着说你需要使用ZwQueryInformationProcess(,ProcessVmCounters,)VM_COUNTERS_EX2 结构并使用PrivateWorkingSetSize 成员如果你想得到与Windows 管理器相同的结果(所有这些都只在win10 上) - 什么这里不清楚吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-26
  • 2015-02-27
  • 1970-01-01
  • 1970-01-01
  • 2022-12-04
  • 2011-08-09
  • 1970-01-01
相关资源
最近更新 更多