VC
++6.0
中内存泄漏检测
摘自:VC知识库BLOG-周星星 网址:blog.vckbase.com/bruceteen/
对
C++
代码而言
,
内存泄漏问题虽然有诸多方法避免
,
但实际代码编写的时候
,
或出于自信或出于复杂性的考虑
,
常常还会用到原始的
operator new,
这不可避免的会带来内存泄漏的可能
,
不久前本人因为违反了
"
可用于被多态继承的基类其析构函数应当有
virtual
修饰
"
的法则
(
一不小心就忘了写
virtual ^_^ ),
导致了内存泄漏
,
因此我觉得出于安全考虑
,
在代码中加入内存泄漏检查机制还是很必要的
,
也因为这次的内存泄漏事件促使我写出这一篇文章
.
VC++
中本身就有内存泄漏检查的机制
,
你可以在向导生成的支持
MFC
的工程中看到如下代码
:
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
通过它们
,
你能非常容易的发现代码中的内存泄漏
,
但是如果手工将这个功能移植到非
MFC
工程中去是很繁琐的一件事
,
另外它还有一个
bug,
在多线程并发调用这个
DEBUG_NEW
时会导致系统级错误
,
因此本人在此重写了这个功能
,
将以下的
debug_new.h
和
debug_new.cpp
添加到工程中
,
并在需要检测的
cpp
中
#include "debug_new.h"
和
main
中一开始处加入
REG_DEBUG_NEW
宏即可
.
1. debug_new.h
源代码
/************************************************************************/
/* comment:
此文件与
debug_new.cpp
配合使用
,
用于在调试期发现内存泄漏
*/
/*
仅在
VC++
编译器中适用
(
包括
Intel C++,
因为它使用了相同的库
) */
/*
作者
:
周星星
http://blog.vckbase.com/bruceteen/ */
/*
版权申明
:
无
,
可任意
使用
,
修改
和
发布
*/
/************************************************************************/
/* sample
#include <iostream>
#include "debug_new.h" // +
using namespace std;
int main( void )
{
REG_DEBUG_NEW; // +
char* p = new char[2];
cout << "--End--" << endl;
return 0;
}
在
VC++ IDE
中按
F5
调试运行将会在
Output
窗口的
Debug
页看到类似如下的提示
:
Dumping objects ->
d:/test.cpp(10) : {45} normal block at 0x003410C8, 2 bytes long.
Data: < > CD CD
Object dump complete.
如果不出现如上提示请
Rebuild All
一次
.
*/
#ifndef _DEBUG_NEW_H_
#define _DEBUG_NEW_H_
#ifdef _DEBUG
#undef new
extern void _RegDebugNew( void );
extern void* __cdecl operator new( size_t, const char*, int );
extern void __cdecl operator delete( void*, const char*, int);
#define new new(__FILE__, __LINE__)
#define REG_DEBUG_NEW _RegDebugNew();
#else
#define REG_DEBUG_NEW
#endif // _DEBUG
#endif // _DEBUG_NEW_H_
2. debug_new.cpp
源代码
/************************************************************************/
/* comment:
此文件与
debug_new.h
配合使用
,
用于在调试期发现内存泄漏
*/
/*
仅在
VC++
编译器中适用
(
包括
Intel C++,
因为它使用了相同的库
) */
/*
作者
:
周星星
http://blog.vckbase.com/bruceteen/ */
/*
版权申明
:
无
,
可任意
使用
,
修改
和
发布
*/
/************************************************************************/
//#include "debug_new.h"
#ifdef _DEBUG
#include <windows.h>
#include <crtdbg.h>
class _CriSec
{
CRITICAL_SECTION criSection;
public:
_CriSec() { InitializeCriticalSection( &criSection ); }
~_CriSec() { DeleteCriticalSection( &criSection ); }
void Enter() { EnterCriticalSection( &criSection ); }
void Leave() { LeaveCriticalSection( &criSection ); }
} _cs;
void _RegDebugNew( void )
{
_CrtSetDbgFlag( _CRTDBG_REPORT_FLAG | _CRTDBG_LEAK_CHECK_DF );
}
void* __cdecl operator new( size_t nSize, const char* lpszFileName, int nLine )
{
// comment 1: MFC
中提供的
debug new
虽然加了锁
,
但我在实际测试的时候发现多线程并发
//
调用的时候还是抛出了系统错误
,
所以我在这里加了一个线程互斥量
.
// comment 2: debug new
和
debug delete
之间需不需要互斥我并不知道
,
保险起见
,
我同样
//
加了线程互斥量
.
// comment 3:
按照
C++
标准规定
,
在
operator new
失败后应当调用
set_new_handler
设置的
//
函数
,
但是
MSDN
中却说
"
头文件
new
中的
set_new_handler
是
stub
的
,
而应该使
//
用头文件
new.h
中的
_set_new_handler",
这简直是滑天下之大稽
.
//
以下是
VC++6.0
中的
set_new_handler
定义
:
// new_handler __cdecl set_new_handler( new_handler new_p )
// {
// assert( new_p == 0 ); // cannot use stub to register a new handler
// _set_new_handler( 0 );
// return 0;
// }
//
所以我也无计可施
,
只能舍弃
set_new_handler
的作用
.
_cs.Enter();
void* p = _malloc_dbg( nSize, _NORMAL_BLOCK, lpszFileName, nLine );
_cs.Leave();
return p;
}
void __cdecl operator delete( void* p, const char* /*lpszFileName*/, int /*nLine*/ )
{
_cs.Enter();
_free_dbg( p, _CLIENT_BLOCK );
_cs.Leave();
}
#endif
3.
事例代码
#include <iostream>
#include "debug_new.h"
using namespace std;
int main( void )
{
REG_DEBUG_NEW;
char* p = new char[2];
p[0] = 'A';
p[1] = 'B';
cout << "--End--" << endl;
return 0;
}
4.
结果输出
在
VC++ IDE
中按
F5
调试运行将会在
Output
窗口的
Debug
页看到类似如下的提示
:
……
Dumping objects ->
d:/test.cpp(10) : {45} normal block at 0x003410C8, 2 bytes long.
Data: <AB> 41 42
Object dump complete.
……