内存泄露.docx

上传人:b****4 文档编号:4052469 上传时间:2022-11-27 格式:DOCX 页数:12 大小:24.56KB
下载 相关 举报
内存泄露.docx_第1页
第1页 / 共12页
内存泄露.docx_第2页
第2页 / 共12页
内存泄露.docx_第3页
第3页 / 共12页
内存泄露.docx_第4页
第4页 / 共12页
内存泄露.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

内存泄露.docx

《内存泄露.docx》由会员分享,可在线阅读,更多相关《内存泄露.docx(12页珍藏版)》请在冰豆网上搜索。

内存泄露.docx

内存泄露

1.msdn在debug模式下的内存结构

(曾今在gaia引擎里看过类似的自己模仿实现的内存管理结构)

typedefstruct_CrtMemBlockHeader

{

//Pointertotheblockallocatedjustbeforethisone:

  struct_CrtMemBlockHeader*pBlockHeaderNext;

//Pointertotheblockallocatedjustafterthisone:

  struct_CrtMemBlockHeader*pBlockHeaderPrev;

  char*szFileName;  //Filename

  intnLine;         //Linenumber

  size_tnDataSize;  //Sizeofuserblock

  intnBlockUse;     //Typeofblock

  longlRequest;     //Allocationnumber

//Bufferjustbefore(lowerthan)theuser'smemory:

  unsignedchargap[nNoMansLandSize]; 

}_CrtMemBlockHeader;

/*Inanactualmemoryblockinthedebugheap,

 *thisstructureisfollowedby:

 *   unsignedchardata[nDataSize];

 *   unsignedcharanotherGap[nNoMansLandSize];//防止内存写越界

 */

The“NoMansLand”buffersoneithersideoftheuserdataareaoftheblockarecurrently4bytesinsize,andarefilledwithaknownbytevalueusedbythedebugheaproutinestoverifythatthelimitsoftheuser’smemoryblockhavenotbeenoverwritten.Thedebugheapalsofillsnewmemoryblockswithaknownvalue.Ifyouelecttokeepfreedblocksintheheap’slinkedlistasexplainedbelow,thesefreedblocksarealsofilledwithaknownvalue.Currently,theactualbytevaluesusedareasfollows:

NoMansLand(0xFD)

The“NoMansLand”buffersoneithersideofthememoryusedbyanapplicationarecurrentlyfilledwith0xFD.

Freedblocks(0xDD)

 Thefreedblockskeptunusedinthedebugheap’slinkedlistwhenthe_CRTDBG_DELAY_FREE_MEM_DFflagissetarecurrentlyfilledwith0xDD.

Newobjects(0xCD)

Newobjectsarefilledwith0xCDwhentheyareallocated.

2._CrtDumpMemLeaks()

msdn说明

The_CrtDumpMemoryLeaksfunctiondetermineswhetheramemoryleakhasoccurredsincethestartofprogramexecution.Whenaleakisfound,thedebugheaderinformationforalloftheobjectsintheheapisdumpedinauser-readableform.When_DEBUGisnotdefined,callsto_CrtDumpMemoryLeaksareremovedduringpreprocessing.

_CrtDumpMemoryLeaksisfrequentlycalledattheendofprogramexecutiontoverifythatallmemoryallocatedbytheapplicationhasbeenfreed.Thefunctioncanbecalledautomaticallyatprogramterminationbyturningonthe_CRTDBG_LEAK_CHECK_DFbitfieldofthe_crtDbgFlagflagusingthe_CrtSetDbgFlagfunction.

_CrtDumpMemoryLeakscalls_CrtMemCheckpointtoobtainthecurrentstateoftheheapandthenscansthestateforblocksthathavenotbeenfreed.Whenanunfreedblockisencountered,_CrtDumpMemoryLeakscalls_CrtMemDumpAllObjectsSincetodumpinformationforalloftheobjectsallocatedintheheapfromthestartofprogramexecution.

Bydefault,internalCrun-timeblocks(_CRT_BLOCK)arenotincludedinmemorydumpoperations.The_CrtSetDbgFlagfunctioncanbeusedtoturnonthe_CRTDBG_CHECK_CRT_DFbitof_crtDbgFlagtoincludetheseblocksintheleakdetectionprocess.

Formoreinformationaboutheapstatefunctionsandthe_CrtMemStatestructure,seetheHeapStateReportingFunctions.Forinformationabouthowmemoryblocksareallocated,initialized,andmanagedinthedebugversionofthebaseheap,seeMemoryManagementandtheDebugHeap.

应用:

#include"stdafx.h"

#include

#ifdef_DEBUG

#defineDEBUG_CLIENTBLOCK  new(_CLIENT_BLOCK,__FILE__,__LINE__)

#else

#defineDEBUG_CLIENTBLOCK

#endif

#define_CRTDBG_MAP_ALLOC

#include

#ifdef_DEBUG

#definenewDEBUG_CLIENTBLOCK

#endif//此部分用于使_CrtDumpMemoryLeaks输出内存泄漏文件名和行号信息默认不会输出相关信息

voidExit

{

   inti=_CrtDumpMemoryLeaks;

   assert(i==0);

}

int_tmain(intargc,_TCHAR*argv[])

{

   atexit(Exit);

   int*p=newint;

   return0;

}

不含红色部分输出:

Detectedmemoryleaks!

Dumpingobjects->

{112}normalblockat0x003AA770,4byteslong.

 Data:

<   >00000000

Objectdumpcomplete.

含红色部分输出:

Detectedmemoryleaks!

Dumpingobjects->

d:

\code\consoletest\consoletest.cpp(21):

{112}clientblockat0x003A38B0,subtype0,4byteslong.

 Data:

<   >00000000

Objectdumpcomplete.

1._CrtDumpMemoryLeaks

确定自程序开始执行以来是否发生过内存泄漏,如果发生过,则转储所有已分配对象。

如果已使用_CrtSetDumpClient安装了挂钩函数,那么,_CrtDumpMemoryLeaks每次转储_CLIENT_BLOCK块时,都会调用应用程序所提供的挂钩函数。

CrtDumpMemoryLeaks()就是显示当前的内存泄漏。

注意是“当前”,也就是说当它执行时,所有未销毁的对象均会报内存泄漏。

因此尽量让这条语句在程序的最后执行。

它所反映的是检测到泄漏的地方。

一般用在MFC中比较准确,在InitInstance里面调用_CrtDumpMemoryLeaks

2.信息输出

Detectedmemoryleaks!

Dumpingobjects->

{52}normalblockat0x006D2498,512byteslong.

?

Data:

<>00000000000000000000000000000000

{51}normalblockat0x006D2440,24byteslong.

?

Data:

<4>10341400FFFFFFFF0000000000000000

Objectdumpcomplete.

3._CrtSetBreakAlloc

知道某个错误分配块的分配请求编号后,可以将该编号传递给_CrtSetBreakAlloc以创建一个断点

_CrtSetBreakAlloc(51);这样可以快速在{51}次内存泄漏处设上断点。

/*****************************************************************************************************/

最快速度找到内存泄漏

许式伟

2006年11月某日

内存管理是C++程序员的痛。

我的《内存管理变革》系列就是试图讨论更为有效的内存管理方式,以杜绝(或减少)内存泄漏,减轻C++程序员的负担。

由于工作忙的缘故,这个系列目前未完,暂停。

文我想换个方式,讨论一下如何以最快的速度找到内存泄漏。

确认是否存在内存泄漏

我们知道,MFC程序如果检测到存在内存泄漏,退出程序的时候会在调试窗口提醒内存泄漏。

例如:

class CMyApp:

 public CWinApp

{

public:

  BOOLInitApplication()

  {

       int* leak =  new  int[10];

       return TRUE;

  }

};

产生的内存泄漏报告大体如下:

Detectedmemoryleaks!

Dumpingobjects ->

c:

\work\test.cpp(186):

{52}normalblockat 0x003C4410, 40 bytes long.

 Data:

 <                 > CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD

Objectdumpcomplete.

这挺好。

问题是,如果我们不喜欢MFC,那么难道就没有办法?

或者自己做?

呵呵,这不需要。

其实,MFC也没有自己做。

内存泄漏检测的工作是VC++的C运行库做的。

也就是说,只要你是VC++程序员,都可以很方便地检测内存泄漏。

我们还是给个样例:

#include 

inline void EnableMemLeakCheck()

{

  _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

}

void main()

{

  EnableMemLeakCheck();

   int* leak =  new  int[10];

}

 运行(提醒:

不要按Ctrl+F5,按F5),你将发现,产生的内存泄漏报告与MFC类似,但有细节不同,如下:

Detectedmemoryleaks!

Dumpingobjects ->

{52}normalblockat 0x003C4410, 40 bytes long.

 Data:

 <                 > CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD

Objectdumpcomplete.

为什么呢?

看下面。

定位内存泄漏由于哪一句话引起的

你已经发现程序存在内存泄漏。

现在的问题是,我们要找泄漏的根源。

一般我们首先确定内存泄漏是由于哪一句引起。

在MFC中,这一点很容易。

你双击内存泄漏报告的文字,或者在Debug窗口中按F4,IDE就帮你定位到申请该内存块的地方。

对于上例,也就是这一句:

  int*leak=newint[10];

这多多少少对你分析内存泄漏有点帮助。

特别地,如果这个new仅对应一条delete(或者你把delete漏写),这将很快可以确认问题的症结。

我们前面已经看到,不使用MFC的时候,生成的内存泄漏报告与MFC不同,而且你立刻发现按F4不灵。

那么难道MFC做了什么手脚?

其实不是,我们来模拟下MFC做的事情。

看下例:

inline void EnableMemLeakCheck()

{

  _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

}

#ifdef_DEBUG

#define new  new(_NORMAL_BLOCK,__FILE__,__LINE__)

#endif

void main()

{

  EnableMemLeakCheck();

   int* leak =  new  int[10];

}

再运行这个样例,你惊喜地发现,现在内存泄漏报告和MFC没有任何分别了。

快速找到内存泄漏

单确定了内存泄漏发生在哪一行,有时候并不足够。

特别是同一个new对应有多处释放的情形。

在实际的工程中,以下两种情况很典型:

创建对象的地方是一个类工厂(ClassFactory)模式。

很多甚至全部类实例由同一个new创建。

对于此,定位到了new出对象的所在行基本没有多大帮助。

   

COM对象。

我们知道COM对象采用ReferenceCount维护生命周期。

也就是说,对象new的地方只有一个,但是Release的地方很多,你要一个个排除。

那么,有什么好办法,可以迅速定位内存泄漏?

答:

有。

在内存泄漏情况复杂的时候,你可以用以下方法定位内存泄漏。

这是我个人认为通用的内存泄漏追踪方法中最有效的手段。

我们再回头看看crtdbg生成的内存泄漏报告:

Detectedmemoryleaks!

Dumpingobjects ->

c:

\work\test.cpp(186):

{52}normalblockat 0x003C4410, 40 bytes long.

 Data:

 <                 > CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD

Objectdumpcomplete.

除了产生该内存泄漏的内存分配语句所在的文件名、行号为,我们注意到有一个比较陌生的信息:

{52}。

这个整数值代表了什么意思呢?

其实,它代表了第几次内存分配操作。

象这个例子,{52}代表了第52次内存分配操作发生了泄漏。

你可能要说,我只new过一次,怎么会是第52次?

这很容易理解,其他的内存申请操作在C的初始化过程调用的呗。

:

有没有可能,我们让程序运行到第52次内存分配操作的时候,自动停下来,进入调试状态?

所幸,crtdbg确实提供了这样的函数:

即long_CrtSetBreakAlloc(longnAllocID)。

我们加上它:

inline void EnableMemLeakCheck()

{

  _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

}

#ifdef_DEBUG

#define new  new(_NORMAL_BLOCK,__FILE__,__LINE__)

#endif

void main()

{

  EnableMemLeakCheck();

  _CrtSetBreakAlloc(52);

   int* leak =  new  int[10];

}

你发现,程序运行到int* leak =  new  int[10];一句时,自动停下来进入调试状态。

细细体会一下,你可以发现,这种方式你获得的信息远比在程序退出时获得文件名及行号有价值得多。

因为报告泄漏文件名及行号,你获得的只是静态的信息,然而_CrtSetBreakAlloc则是把整个现场恢复,你可以通过对函数调用栈分析(我发现很多人不习惯看函数调用栈,如果你属于这种情况,我强烈推荐你去补上这一课,因为它太重要了)以及其他在线调试技巧,来分析产生内存泄漏的原因。

通常情况下,这种分析方法可以在5分钟内找到肇事者。

当然,_CrtSetBreakAlloc要求你的程序执行过程是可还原的(多次执行过程的内存分配顺序不会发生变化)。

这个假设在多数情况下成立。

不过,在多线程的情况下,这一点有时难以保证。

 

附加说明:

对“内存管理”相关的技术感兴趣?

这里可以看到我的所有关于内存管理的文章。

/****************************************************************************************************************/

                                                 VC使用CRT调试功能来检测内存泄漏

                                                                    作者:

JerryZ

C/C++编程语言的最强大功能之一便是其动态分配和释放内存,但是中国有句古话:

“最大的长处也可能成为最大的弱点”,那么C/C++应用程序正好印证了这句话。

在C/C++应用程序开发过程中,动态分配的内存处理不当是最常见的问题。

其中,最难捉摸也最难检测的错误之一就是内存泄漏,即未能正确释放以前分配的内存的错误。

偶尔发生的少量内存泄漏可能不会引起我们的注意,但泄漏大量内存的程序或泄漏日益增多的程序可能会表现出各种各样的征兆:

从性能不良(并且逐渐降低)到内存完全耗尽。

更糟的是,泄漏的程序可能会用掉太多内存,导致另外一个程序垮掉,而使用户无从查找问题的真正根源。

此外,即使无害的内存泄漏也可能殃及池鱼。

  幸运的是,VisualStudio调试器和C运行时(CRT)库为我们提供了检测和识别内存泄漏的有效方法。

下面请和我一起分享收获——如何使用CRT调试功能来检测内存泄漏?

一、如何启用内存泄漏检测机制

  VC++IDE的默认状态是没有启用内存泄漏检测机制的,也就是说即使某段代码有内存泄漏,调试会话的Output窗口的Debug页不会输出有关内存泄漏信息。

你必须设定两个最基本的机关来启用内存泄漏检测机制。

  一是使用调试堆函数:

#define_CRTDBG_MAP_ALLOC

#include

#include

  注意:

#include语句的顺序。

如果更改此顺序,所使用的函数可能无法正确工作。

  通过包含crtdbg.h头文件,可以将malloc和free函数映射到其“调试”版本_malloc_dbg和_free_dbg,这些函数会跟踪内存分配和释放。

此映射只在调试(Debug)版本(也就是要定义_DEBUG)中有效。

发行版本(Release)使用普通的malloc和free函数。

#define语句将CRT堆函数的基础版本映射到对应的“调试”版本。

该语句不是必须的,但如果没有该语句,那么有关内存泄漏的信息会不全。

  二是在需要检测内存泄漏的地方添加下面这条语句来输出内存泄漏信息:

_CrtDumpMemoryLeaks();

  当在调试器下运行程序时,_CrtDumpMemoryLeaks将在Output窗口的Debug页中显示内存泄漏信息。

比如:

Detectedmemoryleaks!

Dumpingobjects->

C:

\Temp\memleak\memleak.cpp(15):

{45}normalblockat0x00441BA0,2byteslong.

Data:

4142

c:

\programfiles\microsoftvisualstudio\vc98\include\crtdbg.h(552):

{

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1