[DEBUG阶段][源码] Visual Studio 下C++内存泄露检测

转自
http://www.cnblogs.com/zouzf/p/4152279.html

相关文章
http://www.cnblogs.com/skynet/archive/2011/02/20/1959162.html
http://blog.csdn.net/KangRoger/article/details/39317503

参考文章:
http://msdn.microsoft.com/zh-cn/library/x98tx3cf.aspx
http://www.cnblogs.com/jianqiang2010/archive/2010/12/02/1894327.html
http://www.cnblogs.com/skynet/archive/2011/02/20/1959162.html


1、在main方法所在的文件里加上如下代码:
//可以定位到发生内存泄露 所在的文件和具体那一行,用于检测 malloc 分配的内存
#define _CRTDBG_MAP_ALLOC 
#include <stdlib.h>
#include <crtdbg.h>

//把分配内存的信息保存下来,可以定位到那一行发生了内存泄露。用于检测 new 分配的内存
#ifdef _DEBUG
#define new   new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

//有用
inline void EnableMemLeakCheck()
{
    //该语句在程序退出时自动调用 _CrtDumpMemoryLeaks(),用于多个退出出口的情况.
    //如果只有一个退出位置,可以在程序退出之前调用 _CrtDumpMemoryLeaks()
   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
}



2、在main方法里开始的地方调用 EnableMemLeakCheck() 方法。到此为止,可以检测的内存泄露的信息里,有一部分是可以定位到具体的文件以及所在的行的,但还是有一些其他工程或者其他文件里如果发生内存泄露还是没有定位到具体的文件和行,这些信息会在vs的输出窗口里看到。如下面的输出,第一处泄露有很具体的定位信息,第二处的泄露却没有。

引用

q:\project_wydxml\wydxmlcreator\project_win32\wydxmlcreator.cpp(52) : {256} normal block at 0x00ABBC40, 200 bytes long.
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
{254} normal block at 0x00ABF6F8, 10 bytes long.
Data: <          > CD CD CD CD CD CD CD CD CD CD



3、对于那些没有定位出具体位置的内存泄露处理如下:记录下该处内存是第几次分配的,比如上面的第三行和第四行表示第二处内存泄露,第三行里 {}里的254表示该处泄露的内存是第 254 次分配的。结束运行,在 EnableMemLeakCheck() 方法 后加上一句代码: _CrtSetBreakAlloc(254); 括号里的参数就是没有得到准确定位的泄露内存的被分配的序数,其他的就别改了,再次运行,程序就会在 分配 第 254 块 内存时进入断点,通过断点堆栈就可以比较方便的知道哪些泄露了。

4、注意事项:对于 new 出来的一些自定义类的对象,直接调用其析构方法时,EnableMemLeakCheck 还是会将其视作没有释放内存的,要直接调用 delete xxx 才行。。。如: A *a = new A();  a->~A(); 会被判做有问题的, delete a 才视作没问题。。。。

5、令外,还有个监控某片代码段是否有内存泄露的,如下。如果有这段代码有泄露,_CrtMemDifference就会比较出来,然后 _CrtMemDumpStatistics输出相关信息。输出的信息没有具体的定位到具体文件具体哪一行,但有时还是有些辅助作用的吧
_CrtMemState s1, s2, s3;
_CrtMemCheckpoint( &s1 );

//your code

CrtMemCheckpoint( &s2 );
if ( _CrtMemDifference( &s3, &s1, &s2) )
     _CrtMemDumpStatistics( &s3 );


全部代码如下:
#include "stdafx.h"
#include <iostream>
#include "wydxml.h"

//可以定位到发生内存泄露 所在的文件和具体那一行,用于检测 malloc 分配的内存
#define _CRTDBG_MAP_ALLOC 
#include <stdlib.h>
#include <crtdbg.h>

//把分配内存的信息保存下来,可以定位到那一行发生了内存泄露。用于检测 new 分配的内存
#ifdef _DEBUG
#define new   new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

//有用
inline void EnableMemLeakCheck()
{
    //该语句在程序退出时自动调用 _CrtDumpMemoryLeaks(),用于多个退出出口的情况.
    //如果只有一个退出位置,可以在程序退出之前调用 _CrtDumpMemoryLeaks()
   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
}


int _tmain(int argc, _TCHAR* argv[])
{
    
    EnableMemLeakCheck();

    //运行到 第 191 次 内存分配的时候停下来
    //_CrtSetBreakAlloc(191);

    char* p = new char[100];
    char* p1 = new char[200];
    char* p2 = (char*)malloc(600);
    delete p;

    getchar();

    //_CrtDumpMemoryLeaks();//这个代码好像会输出额外多余的内存分配信息
    return 0;
}



以下转自
http://www.cnblogs.com/huhuuu/p/3576710.html

C++没有java的内存垃圾回收机制,在程序短的时候可能比较容易发现问题,在程序长的时候是否有什么检测的方法呢?

  假设有一个函数可以某点检测程序的内存使用情况,那是否可以在程序开始的时候设置一个点,在程序结束的时候再设置一个点,比较这两个值是否一样就可以知道内存泄露的情况了。

  windows下的内存检测方法:
#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;
    int n=1000;
    GetMemory(str, 100);//这里申请后没有释放内存,内存泄露了

    _CrtMemCheckpoint( &s2 ); 

    _CrtMemDifference( &s3, &s1, &s2); //比较s1,s2的内存差异,结果放s3
    printf("%ud",s3.lTotalCount);

    return 0;
}


    之前一直没有搞清楚_CrtDumpMemoryLeaks();的调用方法,因为之前执行程序都是ctrl + F5的,原来发现这个函数是在F5的时候生效

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK  new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

int main()
{
    
    int* p = new int(); 
    int n=5;
    while(n--){
        new int;
    }
    _CrtDumpMemoryLeaks();

    return 0;
}




嗯,编译器提示有6个内存块内存泄露了。

同时,注意其中也显示了内存泄露的行号,利于调试。



在linux下也有类似的方法

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

猜你喜欢

转载自jacky-dai.iteye.com/blog/2310685