gpt4 book ai didi

c++ - 在Windows中获得准确的堆使用情况(用于在单个进程中调试内存泄漏)

转载 作者:行者123 更新时间:2023-12-01 14:58:39 25 4
gpt4 key购买 nike

我作为嵌入式软件开发人员已经工作了多年,在其中内存泄漏(甚至最小量的内存)通常非常关键。
在这些环境中,通常可以评估已用堆的数量,而仅通过在代码关键点上打印已用内存的总量,就至少可以进行基本/粗糙的内存泄漏调试。
现在,我正在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", header, pmc.PageFaultCount, pmc.PageFaultCount);
printf("%s:\tPeakWorkingSetSize\t\t= %d 0x%08X\n", header, pmc.PeakWorkingSetSize, pmc.PeakWorkingSetSize);
printf("%s:\tWorkingSetSize\t\t\t= %d 0x%08X\n", header, pmc.WorkingSetSize, pmc.WorkingSetSize);
printf("%s:\tQuotaPeakPagedPoolUsage\t\t= %d 0x%08X\n", header, pmc.QuotaPeakPagedPoolUsage, pmc.QuotaPeakPagedPoolUsage);
printf("%s:\tQuotaPagedPoolUsage\t\t= %d 0x%08X\n", header, pmc.QuotaPagedPoolUsage, pmc.QuotaPagedPoolUsage);
printf("%s:\tQuotaPeakNonPagedPoolUsage\t= %d 0x%08X\n", header, pmc.QuotaPeakNonPagedPoolUsage, pmc.QuotaPagedPoolUsage);
printf("%s:\tQuotaNonPagedPoolUsage\t\t= %d 0x%08X\n", header, pmc.QuotaNonPagedPoolUsage, pmc.QuotaNonPagedPoolUsage);
printf("%s:\tPagefileUsage\t\t\t= %d 0x%08X\n", header, pmc.PagefileUsage, pmc.PagefileUsage);
printf("%s:\tPeakPagefileUsage\t\t= %d 0x%08X\n", header, pmc.PeakPagefileUsage, pmc.PeakPagefileUsage);

printf( "%s:\tPrivateUsage\t\t\t= %d 0x%08X\n", header, 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问题的大多数答案, WorkingSetSizePrivateUsage字段是提供我所需信息的最佳人选。无论如何,为了提供一个完整的方案,我将发布所有结果:
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字节的开销)
  • 内存释放后,其值 IS N'T 减小(!!!)
  • 我本来希望在一定时间后将未使用的虚拟内存返回给操作系统(这就是为什么我尝试在每个步骤之后插入5s sleep 的原因),但看来我是错误的
  • WorkingSetSize似乎也会在每次分配后增长,但是据我所知
  • 的增长量是不一致的

    任何帮助将非常感激。我对我无法找到的任何魔术函数(获得准确的堆使用量)和任何变通方法(例如,迫使 PrivateUsage显示的已用虚拟内存进行更新的东西)都开放。

    最佳答案

    对于您似乎想做的事情,PrivateUsage是一个完全可以接受的指标。
    之所以得到0x21000而不是0x20000的原因是因为该分配在malloc或new返回的地址之前有一个 header (以便正确释放该分配),因此内存中没有任何内容可以满足请求,并且底层操作系统调用为了为该进程获取更多的内存,最终将返回页面数倍的内容,因此它必须舍入为页面大小的倍数。
    测试期间PrivateUsage的值不会下降的原因可能是因为保存了相关的缓冲区以满足将来的请求。为了验证这一猜测,您可以重复执行新的和免费的部分,以便获得“NEW2”报告和“FREE2”报告。对于PrivateUsage,我希望“NEW2”的输出与“FREE”的输出相同。

    关于c++ - 在Windows中获得准确的堆使用情况(用于在单个进程中调试内存泄漏),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58697105/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com