跟踪C++内存分配

Bus*_*icK 47 c++ visualization memory-management

我正在寻找一种方法来跟踪C++程序中的内存分配.我对内存泄漏感兴趣,这似乎是大多数工具试图找到的,而是为应用程序创建内存使用情况配置文件.理想输出可以是函数名称的大列表加上随时间推移的最大分配字节数,也可以是更好的堆积随时间变化的图形表示.横轴是时间,纵轴堆空间.每个函数都会获得它自己的颜色,并根据分配的堆字节绘制线条.用于识别分配的对象类型的加分点.

我们的想法是找到内存瓶颈/可视化哪些函数/线程消耗最多的内存,并且应针对进一步优化.

我简要地看了一下Purify,BoundsChecker和AQTime,但它们似乎并不像我追求的那样.Valgrind看起来很合适,但是,我在Windows上.Memtrack看起来很有前景,但需要对源代码进行重大更改.

我的谷歌技能一定让我失望了,因为它似乎不是这么罕见的要求吗?创建这样的工具所需的所有信息都应该可以从程序的调试符号和运行时API调用中获得 - 不是吗?

小智 31

使用Valgrind及其工具Massif.它的示例输出(它的一部分):

99.48% (20,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->49.74% (10,000B) 0x804841A: main (example.c:20)
| 
->39.79% (8,000B) 0x80483C2: g (example.c:5)
| ->19.90% (4,000B) 0x80483E2: f (example.c:11)
| | ->19.90% (4,000B) 0x8048431: main (example.c:23)
| |   
| ->19.90% (4,000B) 0x8048436: main (example.c:25)
|   
->09.95% (2,000B) 0x80483DA: f (example.c:10)
  ->09.95% (2,000B) 0x8048431: main (example.c:23)
Run Code Online (Sandbox Code Playgroud)

那么,您将获得详细信息:

  • 世界卫生组织分配了内存(函数:上例中的g(),f()和main()); 你也得到完整的回溯导致分配功能,
  • 到内存的WHICH数据结构(上例中没有数据结构),
  • 发生的时候,
  • 所有分配内存的PERCENTAGE是多少(g:39.7%,f:9.95%,主要:49.7%).

这是Massif手册

您可以跟踪堆分配以及堆栈分配(默认情况下已关闭).

PS.我刚看到你在Windows上.我会留下答案,因为它给出了一个可以从一个可能的工具中获得的图片.


Nit*_*ide 19

微软有很好的记录跟踪功能.但是,由于某些原因,它们在开发人员社区中并不是很有名.这些是CRT调试功能.好的起点将是CRT Debug Heap功能.

有关详细信息,请查看以下链接

  1. 堆状态报告功能
  2. 跟踪堆分配请求.这可能是您正在寻找的功能.


Ski*_*izz 14

对于通用C++内存跟踪器,您需要重载以下内容:

global operator new
global operator new []
global operator delete
global operator delete []
any class allocators
any in-place allocators
Run Code Online (Sandbox Code Playgroud)

棘手的一点是获取有用的信息,重载的运算符只有分配器的大小信息和删除的内存指针.一个答案是使用宏.我知道.讨厌.示例 - 放置在包含在所有源文件中的标头中:

#undef new

void *operator new (size_t size, char *file, int line, char *function);
// other operators

#define new new (__FILE__, __LINE__, __FUNCTION__)
Run Code Online (Sandbox Code Playgroud)

并创建一个源文件:

void *operator new (size_t size, char *file, int line, char *function)
{
  // add tracking code here...
  return malloc (size);
}
Run Code Online (Sandbox Code Playgroud)

以上只有在类范围内没有定义任何运算符时才有效.如果你确实有类范围,请执行:

#define NEW new (__FILE__, __LINE__, __FUNCTION__)
Run Code Online (Sandbox Code Playgroud)

并将'new type'替换为'NEW type',但这需要潜在地更改大量代码.

由于它是一个宏,删除内存跟踪器非常简单,标题变为:

#if defined ENABLED_MEMORY_TRACKER
#undef new

void *operator new (size_t size, char *file, int line, char *function);
// other operators

#define NEW new (__FILE__, __LINE__, __FUNCTION__)
#else
#define NEW new
#endif
Run Code Online (Sandbox Code Playgroud)

和实施文件:

#if defined ENABLED_MEMORY_TRACKER
void *operator new (size_t size, char *file, int line, char *function)
{
  // add tracking code here...
  return malloc (size);
}
endif
Run Code Online (Sandbox Code Playgroud)


Bus*_*icK 7

监控PC的内存使用情况对于游戏开发来说,它包含了我所寻找的几乎完美的示例.它需要一段时间才能运行,但文章的作者非常有帮助.你可以在这里找到Memtracer工具的源代码.

我在SWENG(软件工程邮件列表)上也得到了很多有用的答案.该线程被称为"[Sweng-Gamedev]监视C++内存使用情况?".


Ade*_*art 7

更新: @Skizz 的回答

从 C++20 开始,我们可以使用std::source_location而不是像__FILE__和那样的宏__LINE__

(由于这是一个重大简化,我相信它值得一个单独的答案)。