VC 2012 年的内存泄漏检测

Memory leaks detection in VC 2012

在旧版本的 Visual C++ 中,调试器能够检测到内存泄漏。 例如下面的代码

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

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
    char *memleak= new char[100];
    memleak[0]='a';
    return 0;
}

应该会产生一条消息,指出存在 100 字节的内存泄漏。像这样:(参见 MSDN

Detected memory leaks! Dumping objects -> {18} normal block at 0x00780E80, 100 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete.

但我无法 "force" 这条消息。 有什么我必须启用的吗?还是我必须安装一些额外的功能? 我正在使用 Studio Prof. 2012 Update 4。

您是否通读了那篇 MSDN 文章?当您使用 new 进行内存分配时,您必须添加这一行:

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

您还可以调用 _CrtDumpMemoryLeaks() 到 "force" 在程序的任何位置输出所有检测到的内存泄漏。不过,我更喜欢在我的应用程序的退出点执行此操作。

@Vinzenz 的回答有些中肯,但我会尽力提供所有细节。您基本上有两个选择 - 要么在程序退出时让调试运行时转储泄漏(这可以通过调用 _CrtSetDbgFlag 并设置 _CRTDBG_LEAK_CHECK_DF 位的标志值来打开内存泄漏报告来完成),或如前所述调用 _CrtDumpMemoryLeaks() 以在随机执行点转储泄漏。由于您的示例不执行任何这些操作,因此您什么也得不到。

_CrtDumpMemoryLeaks() 的重要之处在于它会转储在调用时尚未释放的堆分配,因此任何智能指针(以及在内部分配堆内存的所有其他对象)未被销毁的将在此时被丢弃。这就是为什么使用报告标志会更好一些,因为它在程序执行结束后运行,因此所有应该销毁的对象都被销毁了。

至于DBG_NEW,它只为您提供额外的行信息,显示导致泄漏的行。没有它,您将获得与问题示例一样的输出,有了它,您将获得导致此问题的行号(请参见下面的示例)。

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

/*

Without the DBG_NEW you get something like, no line info

Detected memory leaks!
Dumping objects ->
{74} normal block at 0x00000000005D6520, 100 bytes long.
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete

With it you get

Detected memory leaks!
Dumping objects ->
strcattest.cpp(36) : {74} normal block at 0x00000000002C6520, 100 bytes long.
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.

*/

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

int main(int argc, char* argv[])
{
    // Enable automatic memory leak reporting at the end of the program, the next 3 lines can be skipped if _CrtDumpMemoryLeaks() is called somewhere
    int current_flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG );
    current_flags |= _CRTDBG_LEAK_CHECK_DF; 
    _CrtSetDbgFlag(current_flags);
    char *memleak= new char[100];
    _CrtDumpMemoryLeaks(); // Trigger dumping the leaks at this point
    return 0;
}