我作为嵌入式软件开发人员已经工作了多年,在该应用程序中,内存泄漏(甚至最小量的内存泄漏)通常非常关键。
在这些环境中,通常可以评估已使用堆的数量,而仅通过在代码关键点上打印已使用的内存总量,就至少可以进行基本/粗糙的内存泄漏调试。
现在,我正在Windows环境中开发C ++解析器,但是...令人惊讶的是,我找不到跟踪此基本信息的方法。所以问题是:我该怎么办?
在回答之前,让我先说一下,出于某些原因我对类似Valgrind的工具不感兴趣。
在问一个新问题之前,我已经阅读了很多以前的问题,例如:
How to get memory usage under Windows in C++
Which member in PROCESS_MEMORY_COUNTERS structure gives the current used memory
How to determine CPU and memory consumption from inside a process?
但是他们都没有提供适合我需要的解决方案。因此,我决定写一个新的问题,明确(1)我真正需要什么,(2)我已经尝试实现目标的尝试。因此,下面提供一个最小的示例程序,在该程序中,我将执行一些128kB(0x20000字节)的分配(以不同的方式),然后执行相应的内存释放。每一步之后,我调用一个debugMemory()
实用程序,该实用程序将打印PROCESS_MEMORY_COUNTERS_EX
结构的每个字段:
#include <stdio.h>
#include <windows.h>
#include <psapi.h>
#define ONE_K 1024
static void debugMemory( const char * header )
{
PROCESS_MEMORY_COUNTERS_EX pmc;
if( header )
{
printf("%s:\t\tGetProcessMemoryInfo() returned %d\n",header,GetProcessMemoryInfo(getcurrentProcess(),(PROCESS_MEMORY_COUNTERS*)&pmc,sizeof(pmc)));
printf("%s:\tPageFaultCount\t\t\t= %d 0x%08X\n",pmc.PageFaultCount,pmc.PageFaultCount);
printf("%s:\tPeakWorkingSetSize\t\t= %d 0x%08X\n",pmc.PeakWorkingSetSize,pmc.PeakWorkingSetSize);
printf("%s:\tWorkingSetSize\t\t\t= %d 0x%08X\n",pmc.WorkingSetSize,pmc.WorkingSetSize);
printf("%s:\tQuotaPeakPagedPoolUsage\t\t= %d 0x%08X\n",pmc.QuotaPeakPagedPoolUsage,pmc.QuotaPeakPagedPoolUsage);
printf("%s:\tQuotaPagedPoolUsage\t\t= %d 0x%08X\n",pmc.QuotaPagedPoolUsage,pmc.QuotaPagedPoolUsage);
printf("%s:\tQuotaPeakNonPagedPoolUsage\t= %d 0x%08X\n",pmc.QuotaPeakNonPagedPoolUsage,pmc.QuotaPagedPoolUsage);
printf("%s:\tQuotaNonPagedPoolUsage\t\t= %d 0x%08X\n",pmc.QuotaNonPagedPoolUsage,pmc.QuotaNonPagedPoolUsage);
printf("%s:\tPagefileUsage\t\t\t= %d 0x%08X\n",pmc.PagefileUsage,pmc.PagefileUsage);
printf("%s:\tPeakPagefileUsage\t\t= %d 0x%08X\n",pmc.PeakPagefileUsage,pmc.PeakPagefileUsage);
printf( "%s:\tPrivateUsage\t\t\t= %d 0x%08X\n",pmc.PrivateUsage,pmc.PrivateUsage );
}
}
int main(void)
{
/* Initial */
debugMemory("INI");
Sleep(5000);
/* Malloc */
char *p1 = (char *) malloc(128 * ONE_K);
debugMemory("MALLOC");
Sleep(5000);
/* New */
char *p2 = new char[128 * ONE_K];
debugMemory("NEW");
Sleep(5000);
/* Free */
free( p1 );
debugMemory("FREE");
Sleep(5000);
/* Delete */
delete[] p2;
debugMemory("DELETE");
return 0;
}
根据对SO问题的大多数答案,字段WorkingSetSize
和PrivateUsage
是提供我所需信息的最佳人选。无论如何,为了提供一个完整的方案,我将发布所有结果:
INI: GetProcessMemoryInfo() returned 1
INI: PageFaultCount = 766 0x000002FE
INI: PeakWorkingSetSize = 2834432 0x002B4000
INI: WorkingSetSize = 2830336 0x002B3000
INI: QuotaPeakPagedPoolUsage = 22448 0x000057B0
INI: QuotaPagedPoolUsage = 22448 0x000057B0
INI: QuotaPeakNonPagedPoolUsage = 4864 0x000057B0
INI: QuotaNonPagedPoolUsage = 4480 0x00001180
INI: PagefileUsage = 1069056 0x00105000
INI: PeakPagefileUsage = 1069056 0x00105000
INI: PrivateUsage = 1069056 0x00105000
MALLOC: GetProcessMemoryInfo() returned 1
MALLOC: PageFaultCount = 794 0x0000031A
MALLOC: PeakWorkingSetSize = 2949120 0x002D0000
MALLOC: WorkingSetSize = 2945024 0x002CF000
MALLOC: QuotaPeakPagedPoolUsage = 22448 0x000057B0
MALLOC: QuotaPagedPoolUsage = 22448 0x000057B0
MALLOC: QuotaPeakNonPagedPoolUsage = 4864 0x000057B0
MALLOC: QuotaNonPagedPoolUsage = 4480 0x00001180
MALLOC: PagefileUsage = 1204224 0x00126000
MALLOC: PeakPagefileUsage = 1204224 0x00126000
MALLOC: PrivateUsage = 1204224 0x00126000
NEW: GetProcessMemoryInfo() returned 1
NEW: PageFaultCount = 797 0x0000031D
NEW: PeakWorkingSetSize = 2961408 0x002D3000
NEW: WorkingSetSize = 2957312 0x002D2000
NEW: QuotaPeakPagedPoolUsage = 22448 0x000057B0
NEW: QuotaPagedPoolUsage = 22448 0x000057B0
NEW: QuotaPeakNonPagedPoolUsage = 4864 0x000057B0
NEW: QuotaNonPagedPoolUsage = 4480 0x00001180
NEW: PagefileUsage = 1339392 0x00147000
NEW: PeakPagefileUsage = 1339392 0x00147000
NEW: PrivateUsage = 1339392 0x00147000
FREE: GetProcessMemoryInfo() returned 1
FREE: PageFaultCount = 797 0x0000031D
FREE: PeakWorkingSetSize = 2961408 0x002D3000
FREE: WorkingSetSize = 2957312 0x002D2000
FREE: QuotaPeakPagedPoolUsage = 22448 0x000057B0
FREE: QuotaPagedPoolUsage = 22448 0x000057B0
FREE: QuotaPeakNonPagedPoolUsage = 4864 0x000057B0
FREE: QuotaNonPagedPoolUsage = 4480 0x00001180
FREE: PagefileUsage = 1339392 0x00147000
FREE: PeakPagefileUsage = 1339392 0x00147000
FREE: PrivateUsage = 1339392 0x00147000
DELETE: GetProcessMemoryInfo() returned 1
DELETE: PageFaultCount = 797 0x0000031D
DELETE: PeakWorkingSetSize = 2961408 0x002D3000
DELETE: WorkingSetSize = 2957312 0x002D2000
DELETE: QuotaPeakPagedPoolUsage = 22448 0x000057B0
DELETE: QuotaPagedPoolUsage = 22448 0x000057B0
DELETE: QuotaPeakNonPagedPoolUsage = 4864 0x000057B0
DELETE: QuotaNonPagedPoolUsage = 4480 0x00001180
DELETE: PagefileUsage = 1339392 0x00147000
DELETE: PeakPagefileUsage = 1339392 0x00147000
DELETE: PrivateUsage = 1339392 0x00147000
让我们总结一下,从这些结果中我们可以理解:
-
PrivateUsage
似乎是我要搜索的字段:每次分配后,它的值都大0x21000(而不是0x20000。但是我可以原谅那些0x1000字节的开销) - 它的值 Isn'在内存取消分配(!!!) 后减小
- 我原本希望在一定时间后将未使用的虚拟内存返还给操作系统(这就是为什么我尝试在每个步骤之后插入5s睡眠的原因),但似乎我错了
-
WorkingSetSize
似乎也会在每次分配后增长,但是据我所知,增长的数量并不一致
任何帮助将不胜感激。我对我无法找到的任何 magic 函数和任何变通方法都开放(例如,迫使PrivateUsage
所示的已用虚拟内存被更新的东西)。>