【内存检测系列】window下windbg内存泄漏检查

摘要:
2.5 ProcessExplorerProcessExplorer1显示句柄详细信息2.查看程序占用的句柄。如果是命名句柄,则可以在代码中直接找到句柄的引用URL:https://www.jianshu.com/p/3c88d5adc7bc3。Windows下的内存泄漏–CRTDBG3.1。检测是否存在内存泄漏。Windows平台下的Visual Studio调试器和C运行库为我们提供了一种检测和识别内存泄漏的有效方法。原理大致如下:内存分配应该在运行时通过CRT实现。只要在分配和释放内存时进行记录,在程序结束时,您可以通过比较分配的内存和释放的内存的记录来确定是否存在内存泄漏。

文章目录

1、使用windbg中的umdh检查

1.1、 工具下载

下载地址:http://www.technlg.net/windows/windgb-download/
注意:最好下载x64位的安装包,因为32位的安装包可能会安装不成功。

1.2、环境配置

计算机-》右击-》属性-》高级系统设置-》环境-》系统变量-》Path-》编辑-》变量值 处后加入:

c:Program FilesDebugging Tools for Windows(x64)
  • 1

注意:此路劲请参考个人的安装路径。

1.3、利用工具umdh(user-mode dump heap)分析

(1)由于在安装路径下有 gflags.exe、umdh.exe 这两个可执行文件,且在步骤2中已加入环境变量,下一步可直接在dos界面输入命令;

(2)桌面左下角-》开始 处输入cmd命令,打开dos界面窗口后,输入命令:gflags.exe,会出现下图,并按照下图进行相关设置:
在这里插入图片描述
在这里插入图片描述
(3)gflags标志设置好后,开启cmd
在这里插入图片描述
键入要定位内存泄露的程序gflags.exe /I memroyleak.exe(程序名称)+ust
如图成功后,开启memoryleak.exe程序,即运行需要测试的程序。

1.4、利用umdh创建heap快照

在这里插入图片描述
命令格式:umdh –pn:memoryleak.exe(程序名称) –f:snap1.log(日志名称)
程序运行一段时间后或者程序占用内存增加时,将memoryleak.exe退出。
然后再次创建heap快照,命令行无差别,snap1.log改为snap2.log或者其他。

设置好程序的符号路径,如下图:
在这里插入图片描述
设置好后可以开始分析heap前后两个快照的差异
在这里插入图片描述
分析差异命令:umdh –d snap1.log snap2.log –f:result.txt
在这里插入图片描述
分析完成后查看结果result.txt,可以指定具体的输出文件夹,不指定的话,输出在桌面的个人文件夹《以自己名字命名的文件夹》

红色为umdh定位出来的泄露点,我们在查看源代码
在这里插入图片描述
这样我们就可以修改代码中内存泄露的地方了。

注意:利用Umdh创建Heap快照 步骤设置程序的符号路径,此符号路径是一个在线网址,因此需要电脑联网;对于我们来说只能通过下载符号离线包的方式,离线包的路径为:

https://developer.microsoft.com/en-us/windows/hardware/download-symbols

关键词:Download Windows Symbol Packages

但是不下载此包,符号路径会自动设置为 %windir%symbols 即windows自带的符号路径,目前未发现问题

参考网址:http://blog.csdn.net/chenyujing1234/article/details/11918987

2、使用windbg中的htrace检查

2.1、准备工作

1 打开windbg
2 File->Symbol File Path,配置好符号文件(PDB)
在这里插入图片描述
3 File->Attache to a Process->可以选择一个运行中的进程,并对其进行调试。
image.png

2.2、快照

1 让程序运行(按F5或输入命令:g)
2 程序执行到想要快照的时候,中断程序(Debug->Break)
3 开启句柄栈回溯(输入命令:!htrace -enable)
4 抓取快照(输入命令:!htrace -snapshot)

2.3 、执行操作,比较差异

1 让程序运行(按F5或输入命令:g)
2 执行操作
3 中断程序(Debug->Break)
4 !htrace -diff

2.4、找到代码行

1 查看泄漏的句柄
从下图中可以看出有一个句柄泄漏,该句柄时通过CreateEvent创建出来的事件,通过栈回溯可以看出该事件创建事件的函数:vlc_tester::on_pB_Open_clicked。
image.png

2 查找具体的代码行
lsa vlc_tester!vlc_tester::on_pB_Open_clicked+0x000000000000002c
从下图中可以看出具体的代码。
image.png

3 如果在栈回溯中看不到有用信息,还可以考虑在代码中打印出线程ID,再与句柄泄漏所在线程对比,确认在哪个线程泄漏的,缩小范围。
4 根据栈回溯的模块或模块地址也能找到是哪个模块泄漏的句柄。

2.5、Process Explorer

Process Explorer
1 显示句柄详细信息
在这里插入图片描述
2 查看程序占用的句柄,如果是命名句柄,可以可以直接在代码中找到该句柄
在这里插入图片描述
参考网址:https://www.jianshu.com/p/3c88d5adc7bc

3、windows下内存泄漏–CRTDBG

3.1、检测是否存在内存泄漏

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

(1)、程序文件开头处包含以下语句,不要更改顺序

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

  通过包括crtdbg.h,将malloc和free函数映射到它们的调试版本,即_malloc_dbg和 _free_dbg,这两个函数将跟踪内存分配和释放。 此映射在调试版本(在其中定义了_DEBUG)中发生。 发布版本使用普通的 malloc 和 free 函数。
  #define 语句将 CRT 堆函数的基版本映射到对应的“Debug”版本。 并非绝对需要该语句;但如果没有该语句,内存泄漏转储包含的有用信息将较少。
(2)、在添加了上述语句之后,可以通过在程序中包括以下语句(通常应恰好放在程序退出位置之前)来转储内存泄漏信息:

_CrtDumpMemoryLeaks();
  • 1

示例代码:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

int main(int argc,char** argv)
{
    char *str = (char*)malloc(20 * sizeof(char));
    _CrtDumpMemoryLeaks();
    return 0;
}

 当在调试器下运行程序时(按F5),_CrtDumpMemoryLeaks将在VS最下栏 “输出”窗口 -》显示输出来源-》调试 中显示内存泄漏信息。如果没有使用#Define _CRTDBG_MAP_ALLOC语句,输出窗口则不显示内存泄漏的具体位置。
注意:
  如果程序总是在同一位置退出,调用 _CrtDumpMemoryLeaks 将非常容易。如果程序从多个位置退出,则无需在每个可能退出的位置放置对 _CrtDumpMemoryLeaks 的调用,而可以在程序开始处包含以下调用:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
 该语句在程序退出时自动调用 _CrtDumpMemoryLeaks。必须同时设置 _CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF两个位域。
示例代码:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

int main(int argc,char** argv)
{
    char *str = (char*)malloc(20 * sizeof(char));
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    return 0;
}

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>


void check_mem()
{
	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
}
 
int main(int argc,char** argv)
{
    char *str = (char*)malloc(20 * sizeof(char));
    atexit(check_mem);
    return 0;
}

注:上述方法在测试调用的第三方库是否存在内存泄漏时,并不能显示泄露函数在哪个文件、哪一行,只会简单的显示,如:

Detected memory leaks!  
Dumping objects ->  
{223} normal block at 0x003CF650, 4 bytes long.  
 Data: <  < > E8 F6 3C 00  

此时,需要在程序的入口处加入:

_CrtSetBreakAlloc(223);

在vs中按F5调试,在堆栈信息中就可以看到泄露的具体位置。其中223表示{223} normal block at 0x003CF650, 4 bytes long.

参考网址:https://msdn.microsoft.com/en-us/library/x98tx3cf.aspx
参考网址:https://www.cnblogs.com/skynet/archive/2011/02/20/1959162.html

from:https://blog.csdn.net/listener51/article/details/104417475?utm_medium=distribute.pc_relevant.none-task-blog-searchFromBaidu-7.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-searchFromBaidu-7.control

免责声明:文章转载自《【内存检测系列】window下windbg内存泄漏检查》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇QTableWidget详解(样式、右键菜单、表头塌陷、多选等)(转)SQL Server 检测到基于一致性的逻辑 I/O 错误 pageid 不正确下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

GDB和WinDbg中调用函数

GDB: 特别简单,直接写调用式子即可,如下图的p word.c_str(),其中word的类型是std::string WinDbg:目前都说是.call命令,说实话我宁愿不用。。。见: http://cfc.kizzx2.com/index.php/tutorial-using-windbg-to-call-arbitrary-functions-w...

C#模拟鼠标键盘控制其他窗口(一)

     编写程序模拟鼠标和键盘操作可以方便的实现你需要的功能,而不需要对方程序为你开放接口。比如,操作飞信定时发送短信等。我之前开发过飞信耗子,用的是对飞信协议进行抓包,然后分析协议,进而模拟协议的执行,开发出了客户端,与移动服务器进行通信,但是这有一些缺点。如果移动的服务器对接口进行变更,我所编写的客户端也要进行相应的升级。如果服务器的协议进行了更改,...

Delphi指针的用法

DELPHI指针的使用 大家都认为,C语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是C语言的灵魂,一点都不为过。同时,这种说法也让很多人产生误解,似乎只有C语言的指针才能算指针。Basic不支持指针,在此不论。其实,Pascal语言本身也是支持指针的。从最初的Pascal发展至今的Object Pascal,可以说在指针运用...

mysql设计表结构数据类型的选择

选择合适的数据类型 在使用MySQL创建数据表的时候会遇到一个问题,如何为字段选择合适的数据类型.比如创建一个员工信息表,每个字段都可以用很多种类型来定义, int,char,float等等. char和varchar char和varchar都是用来存储字符串类型的数据,但是他们保存和检索的方式不一样.char属于固定长度的字符类型,二varchar属于...

Windbg实用手册

Windbg工作中用的不多,所以命令老是记不住,每次使用都要重新查命令,挺烦。 趁这次培训的机会好好测试和总结了一下,下次再用就方便多了。 在这里一起共享一下,如果有错误,请指正。 基本知识和常用命令 (1) Windbg下载地址http://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx...

oracle函数,查询,事务

函数包括:单行函数,多行函数(分组函数) 数值函数: --绝对值 select abs(-12.3) fromdual; --向上取值 select ceil(5.3) fromdual; --向下取值 select floor(5.3 )fromdual; --四舍五入 select round(123.4124,2)fromdual; --截取小数点...