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;
}
在旧版本的 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;
}