1. VC自带的CRT:_CrtCheckMemory 调试器和 CRT 调试堆函数
主要适用于:win32,在mfc平台直接使用AfxDumpMemoryLeaks。不需要引用头文件和define任何东西
该函数只在Debug版本才有用,当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在“Output(输出)”窗口中显示内存泄漏信息。但是这个函数只能输出是否有内存泄漏,并不能定位到哪里出现了内存泄漏,因此我们需要参考mfc的方式来加入文件名称和代码行号。
一是包含调试堆函数库文件:
#include<crtdbg.h>
二是在需要检测内存泄漏的地方添加下面这条语句来输出内存泄漏信息:
_CrtDumpMemoryLeaks();
最好在代码中增加
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
宏定义,可以输出内存泄漏具体的文件位置信息。
#include<crtdbg.h>
#ifdef _DEBUG
#define new new( _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
int main()
{
int* p = new int[10];
_CrtDumpMemoryLeaks();
return 0;
}
注意:如果程序总是在同一位置退出,调用 _CrtDumpMemoryLeaks 将非常容易。 如果程序从多个位置退出,则无需在每个可能退出的位置放置对_CrtDumpMemoryLeaks 的调用,而可以在程序开始处包含以下调用:
1 |
|
该语句在程序退出时自动调用 _CrtDumpMemoryLeaks。 必须同时设置 _CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF 两个位域。
2.使用Visual Leak Detector(VLD)
VLD的最新版本为2.5.1,下载地址: VLD2.5.1。这个是别人弄好的下载。
或者使用该链接: https://pan.baidu.com/s/12GUr8MhUEzSO1YYTTS4Edg 提取码: 6rgj
下载到的软件是:vld-2.5.1-setup.exe 。安装后,其安装目录为:
也可以到官网下载,下载地址为:https://kinddragon.github.io/vld/
配置VLD
打开VS2017,创建一个新工程,在资源管理器中项目右键,点击属性,进入项目属性页进行配置,用这种方法配置只能在本项目中使用VLD。若想一劳永逸,使所有项目都能使用VLD,则需要从属性管理器中进入“Microsoft.Cpp.x64.user”属性页(64位)或者“Microsoft.Cpp.Win32.user”属性页(32位)。本文从项目属性页对其进行配置。
设置 配置属性->VC++目录->包含目录:安装目录\include
设置 配置属性->VC++目录->库目录:安装目录\lib
注意事项:
1.不需要在链接器->输入->附加依赖项中添加xx.lib 文件
2.也不需要把dll放在运行目录下
如果是在安装exe时,选择把vld安转到vs环境中,会自动为项目设置继承,不需要再手动添加include和lib文件了,相当于跳过这一步。
定位显示行号
配置属性->链接器->所有选项->生成调试信息 选择“生成经过优化以共享和发布的调试信息(/DEBUG:FULL)”,然后点击确定
另外还有一种办法显示行号:没测试过
需要更新dbghelp.dll,具体方法为:将VS2017 的dbghelp放到VLD里,替换VLD目录下的dbhelp.dll
VS2017 的dbghelp的路径为:
%programfiles(x86)%\Microsoft Visual Studio\2017\版本类型\Common7\IDE\CommonExtensions\Microsoft\TestWindow\Extensions\Cpp
添加头文件
如果是没有预编译头,直接在main函数所在的cpp最前面加上#include "vld.h",
若是有预编译头且是mfc程序,这最好在预编译头里#include <afxwin.h>前加上#include "vld.h"
如即一般放在stdafx.h或者pch.h文件前面位置。也就满足 如果有include"stdafx.h",则#include "vld.h"放在其后,否则放在最前面。
这个时候如果代码路径里没有中文,应该就可以正常使用了。但是如果有中文的话可能会出现:无法显示Call Stack文,得不到具体泄露的位置的问题。解决方法为:编辑VLD安装目录下的配置文件vld.ini,将ReportEncoding = ascii改为ReportEncoding = unicode就可以了。
测试现象和结果
同时默认的情况下,会在源码工程目录下生成memory_leak_report.txt报告
如果有了调试信息,但在源码工程目录下没看到memory_leak_report.txt。是因为vld.ini 文件缺省配置为ReportTo = debugger 。应该改成ReportTo = both。
如果同时exe和多个dll,需要在每个exe和dll都要#include "vld.h",这样才能有内存泄漏日志产生。
如果只设置dll有#include "vld.h",并且产生了内存泄漏日志,则日志保存在dll的源码工程下,否则在exe的源码工程下。
注意事项:
1 如果有include"stdafx.h",则include <vld.h>放在其后,否则放在最前面
2 VLD只在debug版本有效
3 如果想将产生的日志保存到文件中,需要将vld.ini(VLD安装目录下)复制到可执行文件目录下,
然后作如下修改:
ReportFile =.\memory_leak_report.txt
ReportTo = both //设置为both,才能会在源码工程目录下生成报告
4.但是只支持MSVC编译器,不支持MingGW编译器。
原理:
在VisualC++中内置工具CRT Debug Heap工具,在使用Debug版本分配内存时,它会在内存块中记录分配该内存的文件名和行号。当程序退出时CRT会在main函数返回时做一些清理工作,此时检查调试堆内存,如果仍然有内存没释放,则一定存在内存泄漏问题。从这些没有被释放的内存块的头中可以得到文件名和行号。这种静态的方法可以检查出内存泄漏,但是不知道泄漏究竟是怎么发生的,也不知道该内存分配语句是如何被执行到的,想要了解这些必须对内存分配过程进行动态跟踪。VLD就是这样做的,在每次内存分配的时候记录其上下文,当程序退出时对检测到的内存泄漏查找其上下文信息,并转换成报告输出到Output中
Visual Leak Detector的工作分为3步,
1)首先在初始化注册一个钩子函数;
2)然后在内存分配时该钩子函数被调用以记录下当时的现场;
3)最后检查堆内存分配链表以确定是 否存在内存泄漏并将泄漏内存的现场转换成可读的形式输出。
3.VS2017的Debug下的诊断工具
简单的程序可以实现记录快照和对比查找泄露位置,但是复杂的程序快照记录没问题,不过对比快照的时候会出现卡住的情况
4.神器:VS2017性能探查器的内存使用率分析(ALT+F2或者菜单调试->性能探查器)
可以做快照对比,能支持Debug和Release,使用后感觉应该是目前我用过最方便直观的内存泄露检测工具。