3

我正在开发一个内存泄漏工具。在这个我重载 new 和 delete 运算符。它工作正常。但是我创建这个工具的代码大约是 15000 行。我无法更改现有代码,只有我可以将 memoryleak 工具功能调用到现有代码中。具有 stl 容器的现有代码(如列表、地图、堆栈等)。Stl 容器还调用 new 和 delete 运算符来分配或释放内存。我希望 stl 容器应该调用不在重载的 new 和 delete 中的 new 和 delete 运算符。例如:

int *iptr = new int[10] ----> should call overloaded new[]
delete [] iptr -------------> should call overloaded delete[]
map.insert(10) -------------> should call default new[] ( which are in new.h)
map.erase()  ---------------> should call default delete[] ( which are in new.h)

我该怎么做?任何帮助将不胜感激。

对不起,我忘了提到我正在用以下宏替换 new 和 delete:

#define new DEBUG_NEW
#define DEBUG_NEW TrackMemory(__FILE__, __LINE__) ->* new
#define delete TrackDelete(__FILE__, __LINE__); delete

这里 TrackMemory 用于跟踪内存,new 用于分配内存,与 delete 相同。我的工具也可以正常工作,但是当 stl 容器进入图片时,它会给出错误的结果,因为它们只使用重载的新容器。请帮帮我

4

3 回答 3

3

从编写这些“空”函数开始。他们将自己替换标准的 new 和 delete :

void *operator new (size_t memorySize);
void *operator new[] (size_t memorySize);
void *operator new (size_t memorySize, const std::nothrow_t &) throw ();
void *operator new[] (size_t memorySize, const std::nothrow_t &) throw ();
void operator delete (void *memoryPointer);
void operator delete[] (void *memoryPointer);
void operator delete (void *memoryPointer, const std::nothrow_t &) throw ();
void operator delete[] (void *memoryPointer, const std::nothrow_t &) throw ();

然后编写单独的函数来分配和释放内存:

void *myNew (size-t memorySize);
void myDelete (void *memoryPointer);

在开头提到的函数中调用你的 myNew 和 myDelete。

使用 HeapAlloc 和 HeapFree 实现 myNew 和 myDelete。

然后创建一个全局变量并像这样标记它(这是 Visual Studio):

#pragma init_seg(lib)

这将确保您的全局变量首先被初始化,最后被清理。

到目前为止,我们已经介绍了基础。要获得真正的泄漏报告功能,您需要在 myNew 函数中存储有关已分配内存的信息。

使用全局变量的析构函数来报告所有泄漏。

此外,您可以使用 StackWalk 来获取调用堆栈,并将其存储在每个内存分配中。

有些人可能想知道为什么要这样做而不是使用其他工具:

  • 根据我的经验,Visual Studio 中的泄漏报告是有限的。它不会向您显示调用堆栈,而只会显示直接调用者,这使其毫无意义。
  • 一些工具使用#define 来替换new、delete、alloc,...,但这在某些情况下会产生问题(例如,称为free 的类方法(在Qt 中看到),或者删除是在标题中完成的,但是 .lib 中的新内容,必须链接(也可以在 Qt 中看到))。
  • 其他工具要求您制作应用程序的交互式快照并在之后进行比较。在我上面的方法中,您可以获得自动泄漏报告(无需手动操作,始终在应用程序结束时,...)。

一旦有了自己的内存管理器,您就可以开始考虑添加其他功能(例如,基于调用堆栈的内存统计信息、查找内存覆盖的技巧、查找删除后重用内存的代码的技巧……)。

于 2011-02-09T14:15:02.490 回答
2

15000行?好吧,在你的代码中替换所有对包装器方法的调用(使用宏来记录new并且可以是第一步),你会很快完成。delete__FILE____LINE__

或使用现有工具,如valgrind

于 2011-02-09T12:43:06.647 回答
0

目前尚不清楚您说您正在重载 operator new 是什么意思。您不能像这样重载标准运算符 new,只能在链接时替换它。当你更换它时,你会失去原来的,这是我见过的最愚蠢的设计。替换也是全球性的。您可以在某些平台(弱符号)上使用特定于平台的链接器技巧来解决此问题。

您可以使用基于类的 operator new 进行某种查找技巧,当然您可以在放置参数上重载 operator new,但我假设您的意思不是这些。

于 2011-02-09T12:42:57.737 回答