2

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

我想要的程序输出是:

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

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

-------------------------------------编辑------------ --------------------------

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

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

4

4 回答 4

2

看看 MS 工具叫做 application verifier 也看看 VS2010 profiler。

于 2012-08-29T16:32:08.147 回答
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)).

而 adelete p;相当于:

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

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

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

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

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

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

因此,您可能必须想出一个聪明的方法来输出您想要输出的日志消息,而不会导致任何新删除发生,或者您必须将新删除运算符重载限制为仅你的框架。对于后者,最简单的就是把它放在一个基类中。另一种选择是使用一点 MACRO 魔法,但这仍然会很麻烦而且很麻烦。

而且,此时,如果您必须创建一个基类(对于所有库的类)来处理创建删除的日志记录(或创建一组宏以放入您创建的每个类中),您可能会最好使用构造函数/析构函数作为打印这些日志消息的地方,并保持新删除操作符不变。

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

为什么不?外部工具(如 Valgrind 之类的 VM,或通用分析器/内存跟踪器)很可能会比您做得更好,侵入性更小。

于 2012-08-29T17:17:34.550 回答
1

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

于 2012-08-29T16:36:54.667 回答
1

这在很大程度上取决于您是只想在开发中还是在生产中进行,以及您的性能要求是什么。对于 Linux 上的开发,您通常会从Valgrind 的 Massif开始,如果您正在寻找更自定义的解决方案和/或生产模式,您可能会考虑将 malloc/calloc/realloc 覆盖代码(我的示例在这里)与libunwind结合起来。

于 2012-08-29T16:37:42.750 回答