C/C++内存泄漏及检测

推荐:

http://www.cnblogs.com/skynet/archive/2011/02/20/1959162.html

直接copy过来的,但是之前研究过,只是忘记了呢,原谅这次的懒惰哈。

Windows平台下的内存泄漏检测

Windows平台下面Visual Studio 调试器和 C 运行时 (CRT) 库为我们提供了检测和识别内存泄漏的有效方法,原理大致如下:内存分配要通过CRT在运行时实现,只要在分配内存和释放内存时分别做好记录,程序结束时对比分配内存和释放内存的记录就可以确定是不是有内存泄漏。在vs中启用内存检测的方法如下:

  • STEP1,在程序中包括以下语句: (#include 语句必须采用上文所示顺序。 如果更改了顺序,所使用的函数可能无法正常工作。)

#define _CRTDBG_MAP_ALLOC

#include <stdlib.h>

#include <crtdbg.h>

通过包括 crtdbg.h,将 mallocfree 函数映射到它们的调试版本,即 _malloc_dbg_free_dbg,这两个函数将跟踪内存分配和释放。 此映射只在调试版本(在其中定义了_DEBUG)中发生。 发布版本使用普通的 mallocfree 函数。

#define 语句将 CRT 堆函数的基版本映射到对应的“Debug”版本。 并非绝对需要该语句;但如果没有该语句,内存泄漏转储包含的有用信息将较少。

  • STEP2, 在添加了上述语句之后,可以通过在程序中包括以下语句(通常应恰好放在程序退出位置之前)来转储内存泄漏信息:

_CrtDumpMemoryLeaks();

此时,完整的代码如下:

#define _CRTDBG_MAP_ALLOC

#include <stdlib.h>

#include <crtdbg.h>

#include <iostream>

using namespace std;

void GetMemory(char *p, int num)

{

p = (char*)malloc(sizeof(char) * num);

}

int main(int argc,char** argv)

{

char *str = NULL;

GetMemory(str, 100);

cout<<"Memory leak test!"<<endl;

_CrtDumpMemoryLeaks();

return 0;

}

当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在“输出”窗口中显示内存泄漏信息。 内存泄漏信息如下所示:

如果没有使用 #define _CRTDBG_MAP_ALLOC 语句,内存泄漏转储将如下所示:

未定义 _CRTDBG_MAP_ALLOC 时,所显示的会是:

  • 内存分配编号(在大括号内)。

  • 块类型(普通、客户端或 CRT)。
  • “普通块”是由程序分配的普通内存。

  • “客户端块”是由 MFC 程序用于需要析构函数的对象的特殊类型内存块。 MFC new 操作根据正在创建的对象的需要创建普通块或客户端块。
  • “CRT 块”是由 CRT 库为自己使用而分配的内存块。 CRT 库处理这些块的释放,因此您不大可能在内存泄漏报告中看到这些块,除非出现严重错误(例如 CRT 库损坏)。

从不会在内存泄漏信息中看到下面两种块类型:

  • “可用块”是已释放的内存块。

  • “忽略块”是您已特别标记的块,因而不出现在内存泄漏报告中。
  • 十六进制形式的内存位置。

  • 以字节为单位的块大小。
  • 前 16 字节的内容(亦为十六进制)。

定义了 _CRTDBG_MAP_ALLOC 时,还会显示在其中分配泄漏的内存的文件。 文件名后括号中的数字(本示例中为 10)是该文件中的行号。

注意:如果程序总是在同一位置退出,调用 _CrtDumpMemoryLeaks 将非常容易。 如果程序从多个位置退出,则无需在每个可能退出的位置放置对 _CrtDumpMemoryLeaks 的调用,而可以在程序开始处包含以下调用:

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

该语句在程序退出时自动调用 _CrtDumpMemoryLeaks。 必须同时设置 _CRTDBG_ALLOC_MEM_DF_CRTDBG_LEAK_CHECK_DF 两个位域,如前面所示。

通过上面的方法,我们几乎可以定位到是哪个地方调用内存分配函数malloc和new等,如上例中的GetMemory函数中,即第10行!但是不能定位到,在哪个地方调用GetMemory()导致的内存泄漏,而且在大型项目中可能有很多处调用GetMemory。如何要定位到在哪个地方调用GetMemory导致的内存泄漏?

定位内存泄漏的另一种技术涉及在关键点对应用程序的内存状态拍快照。 CRT 库提供一种结构类型 _CrtMemState,您可用它存储内存状态的快照:

_CrtMemState s1, s2, s3;

若要在给定点对内存状态拍快照,请向 _CrtMemCheckpoint 函数传递 _CrtMemState 结构。 该函数用当前内存状态的快照填充此结构:

_CrtMemCheckpoint( &s1 );

通过向 _CrtMemDumpStatistics 函数传递 _CrtMemState 结构,可以在任意点转储该结构的内容:

_CrtMemDumpStatistics( &s1 );

若要确定代码中某一部分是否发生了内存泄漏,可以在该部分之前和之后对内存状态拍快照,然后使用 _CrtMemDifference 比较这两个状态:

_CrtMemCheckpoint( &s1 );

// memory allocations take place here

_CrtMemCheckpoint( &s2 );

if ( _CrtMemDifference( &s3, &s1, &s2) )

_CrtMemDumpStatistics( &s3 );

顾名思义,_CrtMemDifference 比较两个内存状态(s1 和 s2),生成这两个状态之间差异的结果(s3)。 在程序的开始和结尾放置 _CrtMemCheckpoint 调用,并使用_CrtMemDifference 比较结果,是检查内存泄漏的另一种方法。 如果检测到泄漏,则可以使用 _CrtMemCheckpoint 调用通过二进制搜索技术来划分程序和定位泄漏。

如上面的例子程序我们可以这样来定位确切的调用GetMemory的地方:

#define _CRTDBG_MAP_ALLOC

#include <stdlib.h>

#include <crtdbg.h>

#include <iostream>

using namespace std;

_CrtMemState s1, s2, s3;

void GetMemory(char *p, int num)

{

p = (char*)malloc(sizeof(char) * num);

}

int main(int argc,char** argv)

{

_CrtMemCheckpoint( &s1 );

char *str = NULL;

GetMemory(str, 100);

_CrtMemCheckpoint( &s2 );

if ( _CrtMemDifference( &s3, &s1, &s2) )

_CrtMemDumpStatistics( &s3 );

cout<<"Memory leak test!"<<endl;

_CrtDumpMemoryLeaks();

return 0;

}

调试时,程序输出如下结果:

这说明在s1和s2之间存在内存泄漏!!!如果GetMemory不是在s1和s2之间调用,那么就不会有信息输出。

时间: 2024-11-01 14:48:51

C/C++内存泄漏及检测的相关文章

内存泄漏及其检测工具

一.什么是内存泄露? 在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费. 通常我们所说的内存泄漏是指堆内存的泄漏.堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内存.应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或del

iOS内存泄漏自动检测工具PLeakSniffer

http://www.cocoachina.com/ios/20160706/16951.html 本文授权转自MrPeak技术分享(公众号:MrPeakTech) 新款Objective-C内存泄漏自动检测工具PLeakSniffer,GitHub地址. 背景 前些天读到WeRead团队分享的一款内存泄漏检测工具MLeaksFinder,恍惚想起早些时候自己也有过编写这样一个小工具的想法,不知道由于什么原因把这事给忘记了.在仔细读过MLeaksFinder源码,了解实现思路之后,发现和自己最初

linux中内存泄漏的检测(二)定制化的malloc/free

<linux中内存泄漏的检测(一)最简单的方法>介绍了最简单的内存泄漏检测方法,这种方法虽然简单,却有很多现实的问题,导致它不能用于实际的生产中. 直接使用这种方法肯定是不现实的,因为: (1)把整个工程里所有调用malloc/free的地方都改成my_malloc/my_free,代码改动很大. (2)通常动态库和静态库的代码是没有权限修改的. 今天就来解决这个问题,动态地决定让程序使用自己的还是系统的内存管理接口. wrap选项 不希望修改产品代码,那么用于申请/释放内存的接口还是mall

C/C++内存泄漏及检测 转

C/C++内存泄漏及检测 2011-02-20 17:51 by 吴秦, 30189 阅读, 13 评论, 收藏, 编辑 “该死系统存在内存泄漏问题”,项目中由于各方面因素,总是有人抱怨存在内存泄漏,系统长时间运行之后,可用内存越来越少,甚至导致了某些服务失败.内存泄漏是最难发现的常见错误之一,因为除非用完内存或调用malloc失败,否则都不会导致任何问题.实际上,使用C/C++这类没有垃圾回收机制的语言时,你很多时间都花在处理如何正确释放内存上.如果程序运行时间足够长,如后台进程运行在服务器上

linux中内存泄漏的检测(四)记录泄漏的大小

<linux中内存泄漏的检测(三)定制化的new/delete>讲到,利用C++的函数重载的特性,使C++的代码,也能方便地为new/delete加上用于检测内存泄漏的统计代码.然而,也因此引入的新的问题. 目前的统计方式仅仅统计申请/释放内存的次数,并没有统计每次申请/释放内存的大小. 这种方法对于C来说是够用了,因为在C中申请和释放的大小是相同的,而在C++中就不一定了. 考虑以下两种情况: (1)申请了子类的空间却只释放了父类的空间 father *pF = new son; delet

VS环境中进行内存泄漏的检测

根据MSDN中的介绍,亲测整理. 本篇比较长,如不愿花费太多时间,可只看第一段和第四段,甚至只看第四段. 内存泄漏,即未能正确释放以前分配的内存,是 C/C++ 应用程序中最难以捉摸也最难以检测到的 Bug 之一.借助 Visual Studio 调试器和 C 运行时 (CRT) 库,可以检测和识别内存泄漏.检测内存泄漏的主要工具是调试器和 C 运行库 (CRT) 调试堆函数. 简单的使用 要调用CRT调试堆函数,需包含头文件<crtdbg.h>. 在程序的退出点之前调用函数 _CrtDump

iOS 内存泄漏的检测方式

内存泄漏的检测方式: 一.静态检测方法 1)手动静态检测 使用XCode分析功能,Product->Analyze 2)自动静态检测 在项目的Build setting中,将Analyze During 'Build'设置为YES 二.动态检测方法 1)Instrument 工具检测 Leaks 2) 第三方的内存检测工具,如MLeaksFinder 三.析构方法dealloc打印 一般来说,在创建工程的时候,我都会在Build Settings启用Analyze During 'Build',

Android内存泄漏的检测流程、捕捉以及分析

https://blog.csdn.net/qq_20280683/article/details/77964208 简述: 一个APP的性能,重度关乎着用户体验,而关于性能检测的一个重要方面,就是内存泄漏,通常内存泄漏的隐藏性质比较强,不同于异常导致的程序Crash,在异常导致的Crash中,我们能够及时的发现程序问题的存在,并通过log日志定位到问题所在的具体位置,然后及时进行解决,而内存泄漏则不同,在APP中存在内存泄漏的情况下,用户在低频率短时间的使用中,并不能察觉到有什么异样,反之,随

linux中内存泄漏的检测(一)最简单的方法

什么是内存泄漏 内存泄漏是指程序动态申请的内存在使用完后没有释放,导致这段内存不能被操作系统回收再利用. 例如这段程序,申请了4个字节的空间但没有释放,有4个字节的内存泄漏. #include <iostream> using namespace std; int main() { int *p = new int(1); cout <<*p<<endl; return 0 } 随着时间的推移,泄漏的内存越来越多,可用的内存越来越少,轻则性能受损,重则系统崩溃. 一般情

linux中内存泄漏的检测(五)记录内存泄漏的代码

到目前为止,先后通过wrap malloc.new函数重载和计算指针内存大小的方法,基本上满足了对内存泄漏检测的需要. 如果发现了内存泄漏,那么就要找到内存泄漏的地方并且修正它了. 茫茫代码,如何去找?如果能根据未释放的内存找到申请它的地方就好了. 我们今天就是要做这个事情. 想要根据内存地址查出申请者的信息,那么在一开始申请的时候就要建立地址与申请者之间的映射. 1.内存地址 内存地址,是一个unsigned long型的数值,用void *来存储也可以.为了避免类型转换,我使用了void *