监控C ++中的内存分配

时间:2012-08-29 16:29:24

标签: c++ memory memory-management new-operator

在源代码中监视内存分配/ de_allocation的最佳方法是什么。 我有一个动态分配大量内存的C ++程序,我想跟踪哪个类正在从哪个对象中释放内存。

我想要的程序输出是:

Creating Object from ClassA, Memory Usage ...
Creating Object from ClassB, Memory Usage ...
...
Freeing  Object from ClassA, Memory Freed ...

我现在正在做的只是重载全局新运营商,但我听说它不是非常安全。 此外,我需要一种不需要更改所有类的方法(即使用基类,所有类都有一个字符串变量ClassName)。

------------------------------------- 修改 - ------------------------------------

1-我不想使用外部工具,需要在代码中执行此操作。

2-如果我重载全局new运算符,我如何访问类名或其他成员?

4 个答案:

答案 0 :(得分:2)

看一下名为应用程序验证程序的MS工具,也看看VS2010分析器。

答案 1 :(得分:1)

我讨厌这个工具来追踪内存泄漏,但是为了监控allocs / dellocs它应该做你想做的事:UMDH

答案 2 :(得分:1)

在很大程度上取决于您是仅在开发中还是在生产中进行,以及您的性能要求是什么。对于Linux上的开发,通常从Valgrind's Massif开始,如果您正在查看更自定义的解决方案和/或生产模式,您可以考虑结合使用malloc / calloc / realloc重写代码(我的示例here)与libunwind

答案 3 :(得分:1)

  

2-如果我重载全局new运算符,我如何访问类名或其他成员?

你做不到。您必须了解new和delete运算符不是直接函数调用。实际上,MyClass* p = new MyClass();之类的语法相当于:

MyClass* p = (MyClass*) malloc(sizeof(MyClass)); // A) allocate the memory.
new(p) MyClass(); // B) call constructor (via placement-new syntax (to illustrate)).

虽然delete p;相当于:

p->~MyClass();  // C) call destructor.
free(p);        // D) free the memory.

当重载new-delete操作符时,编译器实际允许您重载的所有操作分别是步骤A)和D)。换句话说,当您到达自定义新运算符的主体时,该对象尚未创建,因此,您无法访问或打印有关它的任何信息(类,名称等),除了它在内存中的地址,你可以打印在你的重载新。类似地,当您到达自定义删除操作符时,该对象已被销毁,并且任何尝试使用可能仍在该内存中悬空的任何信息都是未定义的行为,尤其是如果您要使用虚函数或字符串值。

实际上,使用这种方法可以做的最好的事情是打印在new运算符中创建的指针,并打印delete运算符删除的指针。

并且,正如其他人所提到的,在new-delete运算符中执行操作时,必须警惕无限递归。例如,一个简单的行,如:

std::cout << "Created pointer: " << reinterpret_cast<std::size_t>(p) << std::endl;

几乎肯定会导致许多调用new和delete(创建临时字符串,扩展缓冲区等)。

所以,你可能要么想出一个聪明的方法来输出你想要输出的日志消息而不会导致任何新的删除,或者你必须将你的new-delete操作符重载限制为仅你的框架的类。对于后者,最简单的方法是将它放在基类中。另一个选择是使用一点MACRO魔法,但这仍然是侵入性和麻烦。

此时,如果你必须创建一个基类(对于所有库的类)来处理这个创建 - 删除的日志记录(或创建一组MACRO来放在你创建的每个类中),您也可以使用构造函数/析构函数作为打印这些日志消息的位置,并使新删除操作符保持不变。

  

1-我不想使用外部工具,需要在代码中执行此操作。

为什么不呢?外部工具(像Valgrind这样的VM,或者一般的分析器/内存跟踪器)很可能会比你更好,更少侵入性工作。