C++ - 使用_CrtDumpMemoryLeaks()进行内存泄漏测试 - 不输出行号

16

我正在使用Visual Studio 2010和SDL开发游戏。我发现了_CrtDumpMemoryLeaks()宏并尝试了一下。调用_CrtDumpMemoryLeaks()确实会将内存泄漏信息打印到输出窗口,但它不会显示出现泄漏的位置。

我阅读了MSDN上的文章《启用内存泄漏检测》,其中解释说,如果我定义_CRTDBG_MAP_ALLOC,它应该输出有问题代码的行号。但在我的情况下并没有发生。 (但是如果我直接使用malloc()而不是使用“new”,则可以使其正常工作)。

这是代码:

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    int *var = new int(5);

    _CrtDumpMemoryLeaks();

    return 0;
}
输出结果如下:
检测到内存泄漏!
正在转储对象 ->
{58} 在 0x007D1510 处的普通块,长度为 4 字节。
 数据:<    > 05 00 00 00 
对象转储完成。

如果 _CrtDumpMemoryLeaks() 在使用“new”进行分配时无法输出行号,则欢迎提出其他实现类似功能的建议。
5个回答

9
当您定义_DEBUG并包含<crtdbg.h>时,您会得到一个重载的operator new,它接受额外的参数,您可以使用这些参数来指定放置new表达式中的文件和行号。
例如:
int* p = new (_NORMAL_BLOCK, __FILE__, __LINE__) int(5);
您可以将此内容包装在条件定义的宏中,例如:
#ifdef _DEBUG
#define DEBUG_NEW_PLACEMENT (_NORMAL_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_NEW_PLACEMENT
#endif

int* p = new DEBUG_NEW_PLACEMENT int(5);

虽然你可以看到有人定义一个宏new来完全隐藏客户端代码中的这个形式,但我个人不建议这样做,因为它会破坏已经有意使用放置新对象的任何内容,并且您必须确保在重新定义new之前包含使用放置新对象的任何头文件(例如许多标准头文件)。这可能会使一些头文件中内联使用的new被忽略而未被“调整”,变得更加容易。


9

谢谢指出。我会删除我的答案,采纳你的答案。另外,你应该把你的回答写得更像一个真正的答案,而不是一个评论。 - Björn Pollex
新版本的VLD如广告所述,帮助找到了一堆小内存泄漏,包括调用栈和行号。太好了。 - Jared Updike
d= (◕‿↼) 可以在 https://github.com/Azure/vld 找到一个活跃的分支(但原始版本自2017年以来已停止,但开源很难被消灭)。 - Top-Master
链接无法使用。 - Amanpreet Kaur

3
你可能需要在引入头文件后使用这些定义。

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

7
首先,这重新定义了new,这有点可怕,并且会破坏任何现有的放置new用法;其次,它需要一个有效的DEBUG_NEW定义,该定义仅在标准VC安装中通过afx.h提供,而这是非常基于MFC的头文件。 - CB Bailey

2

Charles Bailey提供的被接受的答案需要你改变源代码,这是不必要的。如果你使用newdelete(或数组版本),你只需要将此代码片段放在每个项目的stdafx.h文件中(包括任何静态或动态库依赖项),它将给出与每个泄露内存对象相关联的源文件和行号:

#ifdef _DEBUG
   #ifndef DBG_NEW
      #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
      #define new DBG_NEW
   #endif
#endif  // _DEBUG

这是直接从微软关于此事的网络页面获取的信息。

在一个大型项目中设置它的正确位置是什么? - a11apurva

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接