现在的位置: 首页 > 综合 > 正文

内存泄漏

2013年09月09日 ⁄ 综合 ⁄ 共 5798字 ⁄ 字号 评论关闭

启用内存泄漏的设定函数:

int _CrtSetDbgFlag(int bits);

返回值:会返回目前的设定,bits是新的值
通常我们会使用 _CRTDBG_REPORT_MODE 获得当前的位
会使用如下方式:

参数:
这里有原文:http://msdn.microsoft.com/en-us/library/5at7yxcs.aspx

简单的说明一下这个地址上面的参数吧:
_CRTDBG_ALLOC_MEM_DF
ON
ON: Enable debug heap allocations and use of memory block type identifiers, such as _CLIENT_BLOCK. OFF: Add new allocations to heap's linked list, but set block type to _IGNORE_BLOCK.
Can also be combined with any of the heap-frequency check macros.
默认这个值是打开的(也就是说如果你不调用这个函数,这个函数里面全局的值就是包含这个值的了)
ON: 表示开启检测内存泄漏;
OFF: 表示所有新的内存分配都放到堆连接表中(我也不知道堆连接表这个表述对不对,有无这个东西也不知道,哈哈),但这个内存块会放到_IGNORE_BLOCK里面的(这些block是什么呢?感觉就是表示一个链表吧)
_CRTDBG_CHECK_ALWAYS_DFOFF
ON: Call _CrtCheckMemory at every allocation and deallocation request. OFF: _CrtCheckMemory must be called explicitly.
Heap-frequency check macros have no effect when this flag is set.
默认是OFF的,如果是ON的话,会在每次分配内存的时候,都会调用 _CrtCheckMemory 函数
_CRTDBG_CHECK_CRT_DF
OFF
ON: Include _CRT_BLOCK types in leak detection and memory state difference operations. OFF: Memory used internally by the run-time library is ignored by these operations.
Can also be combined with any of the heap-frequency check macros.

_CRTDBG_DELAY_FREE_MEM_DF
OFF
ON: Keep freed memory blocks in the heap's linked list, assign them the _FREE_BLOCK type, and fill them with the byte value 0xDD. OFF: Do not keep freed blocks in the heap's linked list.
Can also be combined with any of the heap-frequency check macros.
ON表示在释放内存的时候,会将内存放到_FREE_BLOCK这个块中
_CRTDBG_LEAK_CHECK_DF
OFF
ON: Perform automatic leak checking at program exit through a call to _CrtDumpMemoryLeaks and generate an error report if the application failed to free all the memory it allocated. OFF: Do not automatically perform leak
checking at program exit.
Can also be combined with any of the heap-frequency check macros.
ON表示在程序结束的时候,将内存泄漏的信息打印到VC的output窗口中。
一般咱们使用的时候:_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF)


使用例子1:
//#define  _CRTDBG_MAP_ALLOC
//#define  _CRTDBG_MAP_ALLOC_NEW

#include <cstdlib>
#include <crtdbg.h>

int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF)
int *pp = (int*)malloc(1024);
int *ppnew = new int[1024];
return 0;

}

点击运行F5进行调试,会有下面这些信息:
Detected memory leaks!
Dumping objects ->
{79} normal block at 0x003F9F48, 4096 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
{78} normal block at 0x003F8638, 1024 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.

第一行是malloc()函数泄漏出来的,第二行是new泄漏出来的
大概的意思是:
{第几次分配内存的时候} 在那个内存块 at 在那个内存地址,内存有多大
Data: <   > 泄漏的内存里面的数据,只有16个字节这里

这里好像少了那么点东西,就只告诉了你有内存泄漏,而且泄漏的内存里面的16个字节是什么内存,如果你只看到这16个字节的内容,在代码量很少的情况下,还是很容易找到的,但如果代码量一上去的话,这里等于只告诉你有内存泄漏,但不知道在哪里!!!等于没有用,所以VC还是提供了两个宏来帮忙干这些事情的!

打开上面的:#define  _CRTDBG_MAP_ALLOC
编译运行,会发现,有下面的输出:
Detected memory leaks!
Dumping objects ->
{79} normal block at 0x00429F48, 4096 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
e:\programmetest\vc2012test\memoryleaktest\memoryleakmain.cpp(11) : {78} normal block at 0x00428638, 1024 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.

第二行的泄漏(malloc产生的)现在有了文件在哪里,第几行的信息了(双击的话可以直接定位到程序的)
而第一行是没有的,因为没有打开#define  _CRTDBG_MAP_ALLOC_NEW这里,打开后的输出是:
Detected memory leaks!
Dumping objects ->
d:\program files (x86)\microsoft visual studio 11.0\vc\include\crtdbg.h(1078) : {79} normal block at 0x00659F48, 4096 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
e:\programmetest\vc2012test\memoryleaktest\memoryleakmain.cpp(11) : {78} normal block at 0x00658638, 1024 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.

这次就两个地方都有了,究竟里面是什么回事呢?打开crtdbg.h文件,可以看到:
#ifdef  _CRTDBG_MAP_ALLOC

#define   malloc(s)             _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#define   calloc(c, s)          _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__)
#define   realloc(p, s)         _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)
#define   _recalloc(p, c, s)    _recalloc_dbg(p, c, s, _NORMAL_BLOCK, __FILE__, __LINE__)
#define   _expand(p, s)         _expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)
#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)
。。。。。。。。
#endif  //_CRTDBG_MAP_ALLOC

这里是使用宏替换了malloc了

#if defined(_CRTDBG_MAP_ALLOC) && defined(_CRTDBG_MAP_ALLOC_NEW)
/* We keep these inlines for back compatibility only;
 * the operator new defined in the debug libraries already calls _malloc_dbg,
 * thus enabling the debug heap allocation functionalities.
 *
 * These inlines do not add any information, due that __FILE__ is expanded
 * to "crtdbg.h", which is not very helpful to the user.
 * 
 * The user will need to define _CRTDBG_MAP_ALLOC_NEW in addition to
 * _CRTDBG_MAP_ALLOC to enable these inlines.
 */

_Ret_notnull_ _Post_writable_byte_size_(_Size) inline void * __CRTDECL operator new(size_t _Size)
        { return ::operator new(_Size, _NORMAL_BLOCK, __FILE__, __LINE__); }

_Ret_notnull_ _Post_writable_byte_size_(_Size) inline void* __CRTDECL operator new[](size_t _Size)
        { return ::operator new[](_Size, _NORMAL_BLOCK, __FILE__, __LINE__); }

#endif  /* _CRTDBG_MAP_ALLOC && _CRTDBG_MAP_ALLOC_NEW */
这里是使用了新的new函数替换了一个普通的函数了
详细的不解析了,自己到ctrdbg.h里面分析一下吧

然后再看一个例子2:
#define  _CRTDBG_MAP_ALLOC
#define  _CRTDBG_MAP_ALLOC_NEW

#include <cstdlib>
#include <crtdbg.h>

int main()
{
//_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
int *pp = (int*)malloc(1024);
_CrtDumpMemoryLeaks();
int *ppnew = new int[1024];

_CrtDumpMemoryLeaks();
return 0;
}

这里直接使用了_CrtDumpMemoryLeaks()函数来在想要的地方查看内存泄漏,得到的输出为:
Detected memory leaks!
Dumping objects ->
e:\programmetest\vc2012test\memoryleaktest\memoryleakmain.cpp(11) : {78} normal block at 0x00578638, 1024 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.
Detected memory leaks!
Dumping objects ->
d:\program files (x86)\microsoft visual studio 11.0\vc\include\crtdbg.h(1078) : {81} normal block at 0x0057A818, 4096 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
e:\programmetest\vc2012test\memoryleaktest\memoryleakmain.cpp(11) : {78} normal block at 0x00578638, 1024 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.

有时候是可以使用这种方法查看你认为可能泄漏的某个地方的,十分方便。

最后就是说一说,在输出内存泄漏的地方,用{}括号包起来的有什么用了,里面的数字是表示在第几次分配的时候发生了内存泄漏。可以使用crtdbg.h里面提供的一个函数:
long _CrtSetBreakAlloc(long _BreakAlloc );
进行中断,_BreakAlloc可以设定为{}里面的数字,如果程序每次的分配情况都是一样的话,_BreakAlloc次就是内存泄漏的时候了,debug中断在这里的时候,就可以看看调用栈了,就能找到问题所在了

抱歉!评论已关闭.