当前位置:首页 » 课程大全 » 内存泄漏检测课程设计

内存泄漏检测课程设计

发布时间: 2021-02-20 23:33:30

❶ 如何检测C++的内存泄漏,用哪些工具

本文浅谈一下C++内存泄漏的检测,首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复。最简单的方法当然是借助于专业的检测工具,比较有名如BoundsCheck工具,功能非常强大,相信做C++开发的人都离不开它。此外就是不使用任何工具,而是自己来实现对内存泄露的监控,分如下两种情况:一. 在 MFC 中检测内存泄漏假如是用MFC的程序的话,很简单。默认的就有内存泄露检测的功能。我们用VS2005生成了一个MFC的对话框的程序,发现他可以自动的检测内存泄露.不用我们做任何特殊的操作. 仔细观察,发现在每个CPP文件中,都有下面的代码:#ifdef _DEBUG #define new DEBUG_NEW #endifDEBUG_NEW 这个宏定义在afx.h文件中,就是它帮助我们定位内存泄漏。 在含有以上代码的cpp文件中分配内存后假如没有删除,那么停止程序的时候,VisualStudio的Output窗口就会显示如下的信息了:Detected memory leaks! Dumping objects -> d:\code\mfctest\mfctest.cpp(80) : {157} normal block at 0x003AF170, 4 bytes long. Data: < > 00 00 00 00 Object mp complete.在Output窗口双击粗体字那一行,那么IDE就会打开该文件,定位到该行,很容易看出是哪出现了内存泄露。二.检测纯C++的程序内存泄露我试了下用VisualStudio建立的Win32 Console Application和Win32 Project项目,结果都不能检测出内存泄露。下面一步一步来把程序的内存泄露检测的机制建立起来。首先,我们需要知道C运行库的Debug版本提供了许多检测功能,使得我们更容易的Debug程序。在MSDN中有专门的章节讲这个,叫做Debug Routines,建议大家先看看里面的内容吧。我们会用到里面很重要的几个函数。

❷ 检测出程序内存泄漏,出现下面的提示,请问一下该怎么解决

虽然说我没有看到你复的源制程序,但是根据我的编程经验,你下一步应该检查一下,在你的源程序中都定义了哪些指针变量?它们是否都成功初始化、并成功分配到了内存?在使用完之后是否进行了成功的释放内存?因为如果只是一味地使用内存,而在使用完毕之后,又不管释放内存的话,势必会造成内存的泄漏。因为内存资源是有限的。另外,就是再检查一下,是否有其他数组越界的错误?例如:以 C 语言为例,虽然定义了一个长度为 100 个元素的整型数组(int num[100] ;),但是在存取该数组的元素时,却使用到了 100 以外的下标(num[102] = 50 ;)?这些都会造成内存泄漏。

❸ 高分求助!!!C内存泄露检测问题

你可以对于malloc进行overload,
在malloc中,进行bufferID,Appchain等信息的输出

❹ 如何检查内存泄露问题

简单说明了一下没有工具的情况如何运用VC库中的工具来检查代码的内存泄漏问题。
一: 内存泄漏
内存泄漏是编程中常常见到的一个问题,内存泄漏往往会一种奇怪的方式来表现出来,基本上每个程序都表现出不同的方式。 但是一般最后的结果只有两个,一个是程序当掉,一个是系统内存不足。 还有一种就是比较介于中间的结果程序不会当,但是系统的反映时间明显降低,需要定时的Reboot才会正常。
有 一个很简单的办法来检查一个程序是否有内存泄漏。就是是用Windows的任务管理器(Task Manager)。运行程序,然后在任务管理器里面查看 “内存使用”和”虚拟内存大小”两项,当程序请求了它所需要的内存之后,如果虚拟内存还是持续的增长的话,就说明了这个程序有内存泄漏问题。 当然如果内存泄漏的数目非常的小,用这种方法可能要过很长时间才能看的出来。
当然最简单的办法大概就是用CompuWare的BoundChecker 之类的工具来检测了,不过这些工具的价格对于个人来讲稍微有点奢侈了。
如果是已经发布的程序,检查是否有内存泄漏是又费时又费力。所以内存泄漏应该在Code的生成过程就要时刻进行检查。
二: 原因
内存泄漏产生的原因一般是三种情况:
分配完内存之后忘了回收;
程序Code有问题,造成没有办法回收;
某些API函数操作不正确,造成内存泄漏。
1. 内存忘记回收,这个是不应该的事情。但是也是在代码种很常见的问题。分配内存之后,用完之后,就一定要回收。如果不回收,那就造成了内存的泄漏,造成内存泄漏的Code如果被经常调用的话,那内存泄漏的数目就会越来越多的。从而影响整个系统的运行。比如下面的代码:
for (int =0;I<100;I++)
{
Temp = new BYTE[100];
}
就会产生 100*100Byte的内存泄漏。
2. 在某些时候,因为代码上写的有问题,会导致某些内存想回收都收不回来,比如下面的代码:
Temp1 = new BYTE[100];
Temp2 = new BYTE[100];
Temp2 = Temp1;
这样,Temp2的内存地址就丢掉了,而且永远都找不回了,这个时候Temp2的内存空间想回收都没有办法。
3. API函 数应用不当,在Windows提供API函数里面有一些特殊的API,比如FormatMessage。 如果你给它参数中有FORMAT_MESSAGE_ALLOCATE_BUFFER,它会在函数内部New一块内存Buffer出来。但是这个 buffer需要你调用LocalFree来释放。 如果你忘了,那就会产生内存泄漏。
三: 检查方法
一 般的内存泄漏检查的确是很困难,但是也不是完全没有办法。如果你用VC的库来写东西的话,那么很幸运的是,你已经有了很多检查内存泄漏的工具,只是你想不 想用的问题了。Visual C++的Debug版本的C运行库(C Runtime Library)。它已经提供好些函数来帮助你诊断你的代码和跟踪内存泄漏。 而且最方便的地方是这些函数在Release版本中完全不起任何作用,这样就不会影响你的Release版本程序的运行效率。
比如下面的例子里面,有一个明细的内存泄漏。当然如果只有这么几行代码的话,是很容易看出有内存泄漏的。但是想在成千上万行代码里面检查内存泄漏问题就不是那么容易了。
char * pstr = new char[5];
lstrcpy(pstr,"Memory leak");
如 果我们在Debug版本的Code里面对堆(Heap)进行了操作,包括malloc, free, calloc, realloc, new 和 delete可以利用VC Debug运行时库中堆Debug函数来做堆的完整性和安全性检查。比如上面的代码,lstrcpy的操作明显破坏了pstr的堆结构。使其溢出,并破坏 了临近的数据。那我们可以在调用lstrcpy之后的代码里面加入 _CrtCheckMemory函数。_CrtCheckMemory函数发现前面的lstrcpy使得pstr的堆结构被破坏,会输出这样的报告:
emory check error at 0x00372FA5 = 0x79, should be 0xFD.
memory check error at 0x00372FA6 = 0x20, should be 0xFD.
memory check error at 0x00372FA7 = 0x6C, should be 0xFD.
memory check error at 0x00372FA8 = 0x65, should be 0xFD.
DAMAGE: after Normal block (#41) at 0x00372FA0.
Normal located at 0x00372FA0 is 5 bytes long.
它 告诉说 pstr的长度应该时5个Bytes,但是在5Bytes后面的几个Bytes也被非法改写了。提醒你产生了越界操作。_CrtCheckMemory 的返回值只有TRUE和FALSE,那么你可以用_ASSERTE()来报告出错信息。 上面的语句可以换成 _ASSERTE(_CrtCheckMemory()); 这样Debug版本的程序在运行的时候就会弹出一个警告对话框,这样就不用在运行时候一直盯着Output窗口看了。这个时候按Retry,就可以进入源 代码调试了。看看问题到底出在哪里。
其他类似的函数还有 _CrtDbgReport, _CrtDoForAllClientObjects, _CrtDumpMemoryLeaks,_CrtIsValidHeapPointer, _CrtIsMemoryBlock, _CrtIsValidPointer,_CrtMemCheckpoint, _CrtMemDifference, _CrtMemDumpAllObjectsSince, _CrtMemDumpStatistics, _CrtSetAllocHook, _CrtSetBreakAlloc, _CrtSetDbgFlag,_CrtSetDumpClient, _CrtSetReportFile, _CrtSetReportHook, _CrtSetReportMode
这 些函数全部都可以用来在Debug版本中检查内存的使用情况。具体怎么使用这些函数就不在这里说明了,各位可以去查查MSDN。在这些函数中用处比较大 的,或者说使用率会比较高的函数是_CrtMemCheckpoint, 设置一个内存检查点。这个函数会取得当前内存的运行状态。 _CrtMemDifference 检查两种内存状态的异同。 _CrtMemDumpAllObjectsSince 从程序运行开始,或者从某个内存检查点开始Dump出堆中对象的信息。还有就是_CrtDumpMemoryLeaks当发生内存溢出的时候Dump出堆 中的内存信息。 _CrtDumpMemoryLeaks一般都在有怀疑是内存泄漏的代码后面调用。比如下面的例子:
#include <windows.h>
#include <crtdbg.h>
void main()
{
char * pstr;
pstr = new char[5];
_CrtDumpMemoryLeaks();
}
输出:
Detected memory leaks! à提醒你,代码有内存泄漏.
Dumping objects ->
{44} normal block at 0x00372DB8, 5 bytes long.
Data: < > CD CD CD CD CD
Object mp complete.
如 果你双击包含行文件名的输出行,指针将会跳到源文件中内存被分配地方的行。当无法确定那些代码产生了内存泄漏的时候,我们就需要进行内存状态比较。在可疑 的代码段的前后设置内存检查点,比较内存使用是否有可疑的变化。以确定内存是否有泄漏。为此要先定义三个_CrtMemState 对象来保存要比较的内存状态。两个是用来比较,一个用了保存前面两个之间的区别。
_CrtMemState Sh1,Sh2,Sh_Diff;
char *pstr1 = new char[100];
_CrtMemCheckPoint(&Sh1); ->设置第一个内存检查点
char *pstr2 = new char[100];
_CrtMemCheckPoint(&Sh2); ->设置第二个内存检查点
_CrtMemDifference(&Sh_Diff, &Sh1, &Sh2); ->检查变化
_CrtMemDumpAllObjectsSince(&Sh_Diff); ->Dump变化
如 果你的程序中使用了MFC类库,那么内存泄漏的检查方法就相当的简单了。因为Debug版本的MFC本身就提供一部分的内存泄漏检查。 大部分的new 和delete没有配对使用而产生的内存泄漏,MFC都会产生报告。这个主要是因为MFC重载了Debug版本的new 和delete操作符, 并且对前面提到的API函数重新进行了包装。在MFC类库中检查内存泄漏的Class就叫 CMemoryState,它重新包装了了_CrtMemState,_CrtMemCheckPoint, _CrtMemDifference, _CrtMemDumpAllObjectsSince这些函数。并对于其他的函数提供了Afx开头的函数,供MFC程序使用。比如 AfxCheckMemory, AfxDumpMemoryLeaks 这些函数的基本用法同上面提到的差不多。 CMemoryState和相关的函数的定义都在Afx.h这个头文件中。 有个简单的办法可以跟踪到这些函数的声明。在VC中找到MFC程序代码中下面的代码, 一般都在X.cpp的开头部分
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
把 光标移到DEBUG_NEW上面 按F12,就可以进入Afx.h中定义这些Class和函数的代码部分。 VC中内存泄漏的常规检查办法主要是上面的两种。当然这两种方法只是针对于Debug版本的Heap的检查。如果Release版本中还有内存泄漏,那么 检查起来就麻烦很多了。
4 .总结:
实际上Heap的内存泄漏问题是相当的好查的。VC的提供的检查工具也不太少,但是如果是栈出了什么问题,恐怕就麻烦很多了。栈出问题,一般不会产生内存泄漏,但是你的代码的逻辑上很有可能会有影响。这个是最最痛苦的事情。 编程,就是小心,小心再小心而已。

❺ C++代码中的内存泄漏检查如何做(一)

在含有以上代码的cpp文件中分配内存后假如没有进行释放,那么停止程序的时候,VisualStudio的Output窗口就会显示一些提示的信息了,试一下:在里面加一句 int* p = new int; 然后调试工程,运行结束后你会看到在Output窗口里输出了1:Detected memory leaks!2:Dumping objects -3:e:\学习\de\de\de.cpp(20) : {290} normal block at 0x004CD7F8, 4 byteslong.4:Data: < CD CD CD CD5:Object mp complete.6:The program '[11088] de.exe: Native' has exited with code 0 (0x0). 告诉我们在20行有内存泄漏,双击这双就会跳到相应的代码行,是不是很方便啊! 我试了下用VisualStudio建立的Win32 Console Application和Win32 Project项目,结果都不能检测出内存泄露。 我们将会使用到里面很重要的几个函数。其中最重要的是 _CrtDumpMemoryLeaks使用这个函数,需要包含头文件crtdbg.h 该函数只在Debug版本才有用,当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在“Output(输出)”窗口中显示内存泄漏信息.写段代码试验一下吧,如下: 这个就会在Output窗口输出如下信息: 虽然输出了有内存泄漏,但是无法看出是那里泄漏了,然后下来看看我们的第二个版本的代码: 它会在Output输出: 已经很清楚我告诉我们是在17行产生的。 然后我们把代码修改正确:1:int_tmain(intargc, _TCHAR* argv[])2:{3:int* p =newint;4:deletep;5:_CrtDumpMemoryLeaks();6:return0;7:}运行后,输出的信息就是正确的了。 所以在写代码的时候除了在产生Dump信息外,最重要的就是在程序退出的时候需要掉用一次_CrtDumpMemoryLeaks(); 假如程序有不止一个出口,那么我们就需要在多个地方都调用该函数。

❻ VC6.0如何启用内存泄漏检测机制

VC++ IDE 的默认状态是没有启用内存泄漏检测机制的,也就是说即使某段代码有内存泄漏,调试会话的 Output 窗口的 Debug 页不会输出有关内存泄漏信息。你必须设定两个最基本的机关来启用内存泄漏检测机制。
一是使用调试堆函数:
#define _CRTDBG_MAP_ALLOC
#include<stdlib.h>
#include<crtdbg.h>
注意:#include 语句的顺序。如果更改此顺序,所使用的函数可能无法正确工作。
通过包含 crtdbg.h 头文件,可以将 malloc 和 free 函数映射到其“调试”版本 _malloc_dbg 和 _free_dbg,这些函数会跟踪内存分配和释放。此映射只在调试(Debug)版本(也就是要定义 _DEBUG)中有效。发行版本(Release)使用普通的 malloc 和 free 函数。
#define 语句将 CRT 堆函数的基础版本映射到对应的“调试”版本。该语句不是必须的,但如果没有该语句,那么有关内存泄漏的信息会不全。
二是在需要检测内存泄漏的地方添加下面这条语句来输出内存泄漏信息:
_CrtDumpMemoryLeaks();
当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在 Output 窗口的 Debug 页中显示内存泄漏信息。比如:
Detected memory leaks!
Dumping objects ->
C:\Temp\memleak\memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.
Data: <AB> 41 42
c:\program files\microsoft visual studio\vc98\include\crtdbg.h(552) : {44} normal block at 0x00441BD0, 33 bytes long.
Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD
c:\program files\microsoft visual studio\vc98\include\crtdbg.h(552) : {43} normal block at 0x00441C20, 40 bytes long.
Data: < C > 08 02 43 00 16 00 00 00 00 00 00 00 00 00 00 00
Object mp complete.
如果不使用 #define _CRTDBG_MAP_ALLOC 语句,内存泄漏的输出是这样的:
Detected memory leaks!
Dumping objects ->
{45} normal block at 0x00441BA0, 2 bytes long.
Data: <AB> 41 42
{44} normal block at 0x00441BD0, 33 bytes long.
Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD
{43} normal block at 0x00441C20, 40 bytes long.
Data: < C > C0 01 43 00 16 00 00 00 00 00 00 00 00 00 00 00
Object mp complete.
根据这段输出信息,你无法知道在哪个源程序文件里发生了内存泄漏。下面我们来研究一下输出信息的格式。第一行和第二行没有什么可说的,从第三行开始:
xx}:花括弧内的数字是内存分配序号,本文例子中是 {45},{44},{43};
block:内存块的类型,常用的有三种:normal(普通)、client(客户端)或 CRT(运行时);本文例子中是:normal block;
用十六进制格式表示的内存位置,如:at 0x00441BA0 等;
以字节为单位表示的内存块的大小,如:32 bytes long;
前16字节的内容(也是用十六进制格式表示),如:Data: <AB> 41 42 等;
仔细观察不难发现,如果定义了 _CRTDBG_MAP_ALLOC ,那么在内存分配序号前面还会显示在其中分配泄漏内存的文件名,以及文件名后括号中的数字表示发生泄漏的代码行号,比如:
C:\Temp\memleak\memleak.cpp(15)
双击 Output 窗口中此文件名所在的输出行,便可跳到源程序文件分配该内存的代码行(也可以选中该行,然后按 F4,效果一样) ,这样一来我们就很容易定位内存泄漏是在哪里发生的了,因此,_CRTDBG_MAP_ALLOC 的作用显而易见。
使用 _CrtSetDbgFlag
如果程序只有一个出口,那么调用 _CrtDumpMemoryLeaks 的位置是很容易选择的。但是,如果程序可能会在多个地方退出该怎么办呢?在每一个可能的出口处调用 _CrtDumpMemoryLeaks 肯定是不可取的,那么这时可以在程序开始处包含下面的调用:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
这条语句无论程序在什么地方退出都会自动调用 _CrtDumpMemoryLeaks。注意:这里必须同时设置两个位域标志:_CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF。
设置 CRT 报告模式
默认情况下,_CrtDumpMemoryLeaks 将内存泄漏信息 mp 到 Output 窗口的 Debug 页, 如果你想将这个输出定向到别的地方,可以使用 _CrtSetReportMode 进行重置。如果你使用某个库,它可能将输出定向到另一位置。此时,只要使用以下语句将输出位置设回 Output 窗口即可:
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
有关使用 _CrtSetReportMode 的详细信息,请参考 MSDN 库关于 _CrtSetReportMode 的描述。
解释内存块类型
前面已经说过,内存泄漏报告中把每一块泄漏的内存分为 normal(普通块)、client(客户端块)和 CRT 块。事实上,需要留心和注意的也就是 normal 和 client,即普通块和客户端块。
normal block(普通块):这是由你的程序分配的内存。
client block(客户块):这是一种特殊类型的内存块,专门用于 MFC 程序中需要析构函数的对象。MFC new 操作符视具体情况既可以为所创建的对象建立普通块,也可以为之建立客户块。
CRT block(CRT 块):是由 C RunTime Library 供自己使用而分配的内存块。由 CRT 库自己来管理这些内存的分配与释放,我们一般不会在内存泄漏报告中发现 CRT 内存泄漏,除非程序发生了严重的错误(例如 CRT 库崩溃)。
除了上述的类型外,还有下面这两种类型的内存块,它们不会出现在内存泄漏报告中。
free block(空闲块):已经被释放(free)的内存块。
Ignore block(忽略块):这是程序员显式声明过不要在内存泄漏报告中出现的内存块。
如何在内存分配序号处设置断点?
在内存泄漏报告中,的文件名和行号可告诉分配泄漏的内存的代码位置,但仅仅依赖这些信息来了解完整的泄漏原因是不够的。因为一个程序在运行时,一段分配内存的代码可能会被调用很多次,只要有一次调用后没有释放内存就会导致内存泄漏。为了确定是哪些内存没有被释放,不仅要知道泄漏的内存是在哪里分配的,还要知道泄漏产生的条件。这时内存分配序号就显得特别有用——这个序号就是文件名和行号之后的花括弧里的那个数字。
例如,在本文例子代码的输出信息中,“45”是内存分配序号,意思是泄漏的内存是你程序中分配的第四十五个内存块:
Detected memory leaks!
Dumping objects ->
C:\Temp\memleak\memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.
Data: <AB> 41 42
......
Object mp complete.
CRT 库对程序运行期间分配的所有内存块进行计数,包括由 CRT 库自己分配的内存和其它库(如 MFC)分配的内存。因此,分配序号为 N 的对象即为程序中分配的第 N 个对象,但不一定是代码分配的第 N 个对象。(大多数情况下并非如此。)
这样的话,你便可以利用分配序号在分配内存的位置设置一个断点。方法是在程序起始附近设置一个位置断点。当程序在该点中断时,可以从 QuickWatch(快速监视)对话框或 Watch(监视)窗口设置一个内存分配断点:
例如,在 Watch 窗口中,在 Name 栏键入下面的表达式:
_crtBreakAlloc
如果要使用 CRT 库的多线程 DLL 版本(/MD 选项),那么必须包含上下文操作符,像这样:
{,,msvcrtd.dll}_crtBreakAlloc
现在按下回车键,调试器将计算该值并把结果放入 Value 栏。如果没有在内存分配点设置任何断点,该值将为 –1。
用你想要在其位置中断的内存分配的分配序号替换 Value 栏中的值。例如输入 45。这样就会在分配序号为 45 的地方中断。
在所感兴趣的内存分配处设置断点后,可以继续调试。这时,运行程序时一定要小心,要保证内存块分配的顺序不会改变。当程序在指定的内存分配处中断时,可以查看 Call Stack(调用堆栈)窗口和其它调试器信息以确定分配内存时的情况。如果必要,可以从该点继续执行程序,以查看对象发生了什么情况,或许可以确定未正确释放对象的原因。
尽管通常在调试器中设置内存分配断点更方便,但如果愿意,也可在代码中设置这些断点。为了在代码中设置一个内存分配断点,可以增加这样一行(对于第四十五个内存分配):
_crtBreakAlloc = 45;
你还可以使用有相同效果的 _CrtSetBreakAlloc 函数:
_CrtSetBreakAlloc(45);
如何比较内存状态?
定位内存泄漏的另一个方法就是在关键点获取应用程序内存状态的快照。CRT 库提供了一个结构类型 _CrtMemState。你可以用它来存储内存状态的快照:
_CrtMemState s1, s2, s3;
若要获取给定点的内存状态快照,可以向 _CrtMemCheckpoint 函数传递一个 _CrtMemState 结构。该函数用当前内存状态的快照填充此结构:
_CrtMemCheckpoint( &s1 );
通过向 _CrtMemDumpStatistics 函数传递 _CrtMemState 结构,可以在任意地方 mp 该结构的内容:
_CrtMemDumpStatistics( &s1 );
该函数输出如下格式的 mp 内存分配信息:
0 bytes in 0 Free Blocks.
75 bytes in 3 Normal Blocks.
5037 bytes in 41 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 5308 bytes.
Total allocations: 7559 bytes.
若要确定某段代码中是否发生了内存泄漏,可以通过获取该段代码之前和之后的内存状态快照,然后使用 _CrtMemDifference 比较这两个状态:
_CrtMemCheckpoint( &s1 );// 获取第一个内存状态快照
// 在这里进行内存分配
_CrtMemCheckpoint( &s2 );// 获取第二个内存状态快照
// 比较两个内存快照的差异
if ( _CrtMemDifference( &s3, &s1, &s2) )
_CrtMemDumpStatistics( &s3 );// mp 差异结果
顾名思义,_CrtMemDifference 比较两个内存状态(前两个参数),生成这两个状态之间差异的结果(第三个参数)。在程序的开始和结尾放置 _CrtMemCheckpoint 调用,并使用 _CrtMemDifference 比较结果,是检查内存泄漏的另一种方法。如果检测到泄漏,则可以使用 _CrtMemCheckpoint 调用通过二进制搜索技术来分割程序和定位泄漏。

❼ 内存泄漏检测原理

先hook系统函数,然后配对检测。

❽ 如何检测内存泄漏

首先,我们检查了代码,发现所有的代码都是用new来分配内存,用delete来释放内存。那么,我们能够用一个全程替换,来替换掉所有的new和delete操作符吗?不能。因为代码的规模太大了,那样做除了浪费时间没有别的任何好处。好在我们的源代码是用C++来写成的,所以,这意味着没有必要替换掉所有的new和delete,而只用重载这两个操作符。对了,值用重载这两个操作符,我们就能在分配和释放内存之前做点什么。这是一个绝对的好消息。我们也知道该如何去做。因为,MFC也是这么做的。我们需要做的是:跟踪所有的内存分配和交互引用以及内存释放。我们的源代码使用Visual C++写成,当然这种解决方法也可以很轻松的使用在别的C++代码里面。要做的第一件事情是重载new和delete操作符,它们将会在所有的代码中被使用到。我们在stdafx.h中,加入:
#ifdef _DEBUG
inline void * __cdecl operator new(unsigned int size,
const char *file, int line)
{
};

inline void __cdecl operator delete(void *p)
{
};
#endif

这样,我们就重载了new和delete操作符。我们用$ifdef和#endif来包住这两个重载操作符,这样,这两个操作符就不会在发布版本中出现。看一看这段代码,会发现,new操作符有三个参数,它们是,分配的内存大小,出现的文件名,和行号。这对于寻找内存泄漏是必需的和重要的。否则,就会需要很多时间去寻找它们出现的确切地方。加入了这段代码,我们的调用new()的代码仍然是指向只接受一个参数的new操作符,而不是这个接受三个参数的操作符。另外,我们也不想记录所有的new操作符的语句去包含__FILE__和__LINE__参数。我们需要做的是自动的让所有的接受一个参数的new操作符调用接受三个参数的new操作符。这一点可以用一点点小的技巧去做,例如下面的这一段宏定义,
#ifdef _DEBUG
#define DEBUG_NEW new(__FILE__, __LINE__)
#else
#define DEBUG_NEW new
#endif
#define new DEBUG_NEW
现在我们所有的接受一个参数的new操作符都成为了接受三个参数的new操作符号,__FILE__和__LINE__被预编译器自动的插入到其中了。然后,就是作实际的跟踪了。我们需要加入一些例程到我们的重载的函数中去,让它们能够完成分配内存和释放内存的工作。这样来做, #ifdef _DEBUG

inline void * __cdecl operator new(unsigned int size,
const char *file, int line)
{
void *ptr = (void *)malloc(size);
AddTrack((DWORD)ptr, size, file, line);
return(ptr);
};
inline void __cdecl operator delete(void *p)
{
RemoveTrack((DWORD)p);
free(p);
};
#endif
另外,还需要用相同的方法来重载new[]和delete[]操作符。这里就省略掉它们了。
最后,我们需要提供一套函数AddTrack()和RemoveTrack()。我用STL来维护存储内存分配记录的连接表。
这两个函数如下:
typedef struct {
DWORD address;
DWORD size;
char file[64];
DWORD line;
} ALLOC_INFO;

typedef list<ALLOC_INFO*> AllocList;

AllocList *allocList;

void AddTrack(DWORD addr, DWORD asize, const char *fname, DWORD lnum)
{
ALLOC_INFO *info;

if(!allocList) {
allocList = new(AllocList);
}

info = new(ALLOC_INFO);
info->address = addr;
strncpy(info->file, fname, 63);
info->line = lnum;
info->size = asize;
allocList->insert(allocList->begin(), info);
};

void RemoveTrack(DWORD addr)
{
AllocList::iterator i;

if(!allocList)
return;
for(i = allocList->begin(); i != allocList->end(); i++)
{
if((*i)->address == addr)
{
allocList->remove((*i));
break;
}
}
};
现在,在我们的程序退出之前,allocList存储了没有被释放的内存分配。为了看到它们是什么和在哪里被分配的,我们需要打印出allocList中的数据。我使用了Visual C++中的Output窗口来做这件事情。
void DumpUnfreed()
{
AllocList::iterator i;
DWORD totalSize = 0;
char buf[1024];

if(!allocList)
return;

for(i = allocList->begin(); i != allocList->end(); i++) {
sprintf(buf, "%-50s: LINE %d, ADDRESS %d %d unfreed ",
(*i)->file, (*i)->line, (*i)->address, (*i)->size);
OutputDebugString(buf);
totalSize += (*i)->size;
}
sprintf(buf, "----------------------------------------------------------- ");
OutputDebugString(buf);
sprintf(buf, "Total Unfreed: %d bytes ", totalSize);
OutputDebugString(buf);
};
现在我们就有了一个可以重用的代码,用来监测跟踪所有的内存泄漏了。这段代码可以用来加入到所有的项目中去。虽然它不会让你的程序看起来更好,但是起码它能够帮助你检查错误,让程序更加的稳定。

❾ 关于如何检测Android的内存泄漏

用leakcanary三方库,会自动帮你收集,方便查看

在build.gradle中添加依赖

debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'

在public class App extends Application的专onCreate()方法中:

LeakCanary.install(this);

运行应属用

具体的位置。特别好用

热点内容
武汉大学学生会辅导员寄语 发布:2021-03-16 21:44:16 浏览:612
七年级学生作文辅导学案 发布:2021-03-16 21:42:09 浏览:1
不屑弟高考成绩 发布:2021-03-16 21:40:59 浏览:754
大学毕业证会有成绩单 发布:2021-03-16 21:40:07 浏览:756
2017信阳学院辅导员招聘名单 发布:2021-03-16 21:40:02 浏览:800
查询重庆2018中考成绩查询 发布:2021-03-16 21:39:58 浏览:21
结业考试成绩怎么查询 发布:2021-03-16 21:28:40 浏览:679
14中医医师资格笔试考试成绩查分 发布:2021-03-16 21:28:39 浏览:655
名著赏析课程标准 发布:2021-03-16 21:27:57 浏览:881
北京大学商业领袖高端培训课程 发布:2021-03-16 21:27:41 浏览:919