C++调试内存泄漏

Posted CodeBowl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++调试内存泄漏相关的知识,希望对你有一定的参考价值。

笔记:之前研究过如何定位内存泄漏,太长时间不用又忘记了,今天把它记下来!
学而时习之

内存泄漏的原因

C++和其他高级语言不同,需要自行管理内存,项目大\\调用多,容易内存泄漏.内存申请释放使用malloc/free和new delete两种方式。
有经验的程序员会对程序中申请内存的地方进行排查,例如malloc或者new关键字的地方进行跟踪,一种情况是我们按照程序逻辑进行了申请和释放,要提防程序在发生异常时没有如我们所期望的那样进行内存释放,此时也应当防止内存泄漏。

排查方法

windows CRT调试(Find memory leaks with the CRT library)

这是最方便的方法。
官方有详细使用描述:官网链接:Find memory leaks with the CRT Library - Visual Studio (Windows) | Microsoft Docs
使用案例:

// debug_new.cpp
// compile by using: cl /EHsc /W4 /D_DEBUG /MDd debug_new.cpp
#define _CRTDBG_MAP_ALLOC
#include <cstdlib>
#include <crtdbg.h>
 
#ifdef _DEBUG
    #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
    // Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
    // allocations to be of _CLIENT_BLOCK type
#else
    #define DBG_NEW new
#endif
 
struct Pod 
    int x;
;
 
void main() 
    Pod* pPod = DBG_NEW Pod;
    pPod = DBG_NEW Pod; // Oops, leaked the original pPod!
    delete pPod;
 
    _CrtDumpMemoryLeaks();//直接打印内存泄漏信息

定位更加准确的地址

//#ifdef _DEBUG
//#define  DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
//#else
//#define  DEBUG_CLIENTBLOCK
//#endif
//#define _CRTDBG_MAP_ALLOC
//#include <stdlib.h>
//#include <crtdbg.h>
//#ifdef _DEBUG
//#define  new DEBUG_CLIENTBLOCK
//#endif
 
//_CrtMemState s1,s2,s3;
 
//_CrtMemCheckpoint(&s1);//记录s1处内存数据
//to do something
//_CrtMemCheckpoint(&s2);//记录s1处内存数据
 
//if (_CrtMemDifference(&s3, &s1, &s2))
//	_CrtMemDumpStatistics(&s3);//内存泄漏,两处内存数据不一致,差异结果返回至s3,打印信息

VS2019自带的诊断工具,可在程序运行时打开诊断工具窗口-----》勾选内存使用率----》启用堆栈快照

VS2019自带的诊断工具,可在程序运行时打开诊断工具窗口-----》勾选内存使用率----》启用堆栈快照

类型视图能根据各种差异,点击左侧箭头所指的视图实例,可准确定位内存泄漏发生点。

VLD(Visual Leak Detector)

简介

Visual C++ 提供了内置的内存泄漏检测,但它的功能充其量只是最小的。此内存泄漏检测器是作为 Visual C++ 提供的内置内存泄漏检测器的免费替代品而创建的。以下是 Visual Leak Detector 的一些功能,内置检测器中不存在这些功能:
为每个泄漏块提供完整的堆栈跟踪,包括可用的源文件和行号信息。

检测大多数(如果不是全部)进程内内存泄漏类型,包括基于 COM 的泄漏和基于纯 Win32 堆的泄漏。

选定的模块(DLL 甚至主 EXE)可以从泄漏检测中排除。

提供泄漏块的完整数据转储(以十六进制和 ASCII 格式)。

可定制的内存泄漏报告:可以保存到文件或发送到调试器,并且可以包含可变级别的详细信息。

其他用于 Visual C++ 的售后泄漏检测器已经可用。但大多数真正流行的,如 Purify 和 BoundsChecker,都非常昂贵。存在一些免费的替代方案,但它们通常太具有侵入性、限制性或不可靠。 Visual Leak Detector 是目前唯一可免费使用的 Visual C++ 内存泄漏检测器,它将上述所有专业级功能整齐地打包在一个易于使用的库中

如何测试自己的项目呢

在自己的工程中引入vld.h文件,并在链接库中配置vld.lib库


设置当前工程为Debug模式,才能显示堆栈相关的调用信息
#### 例子

#include<stdlib.h>
#include<stdio.h>
#include <iostream>
#include <vld.h>
#include "three.h"
using namespace std;
 class three

public:
    three();
    ~three();
;
int main()

    cout << "vld test begin" << endl;
    int *one = new int[30];
    char *two = new char[40];
    three * tmp = new three();
    return 0;

程序执行完之后会在终端显示内存泄漏的的个数,并同时会打印相关的内存泄漏的堆栈信息,当鼠标点击终端信息输出的位置时,同时会在上方代码指示哪一行出现内存泄漏。

参考资料

https://www.jb51.net/article/224934.htm

在网上看到的一种有趣的自己排查的方法

https://www.jb51.net/article/246468.htm
通过联想到内存的申请释放方式,申请和释放总是配对的,申请的大小也是预先知道的.**在内存申请申请释放的时候加上内存地址打印,当内存泄漏报错的时候就可以定位出错内存地址在哪个范围.**我加入了一个内存打印函数,把内存地址范围和时间都打印出来.

void DebugHeap(CString name, void * ptr,int size)

    long Time = GetCurrentTime();
    TRACE("========>heap name:%s,address [%p:%p],time:%d (ms)\\n", name,ptr,(char *)ptr + size,Time);

哈哈哈其实和系统提供的方法是相似的,凭借自己想到还是挺厉害的,但是不推荐。

以上是关于C++调试内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

在 Visual C++ (Windows) 中检测内存泄漏

如何检测内存泄漏

如何用VS工具检测内存泄露

如何在linux下检测内存泄漏

使用VS2013编写c++程序时怎样检测内存泄漏

内存泄漏单元测试 C++