博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
umdh windbg分析内存泄露
阅读量:4599 次
发布时间:2019-06-09

本文共 4732 字,大约阅读时间需要 15 分钟。

A.利用工具umdh(user-mode dump heap)分析:此处以程序MemoryLeak.exe为例子

1、开启cmd

                

键入要定位内存泄露的程序gflags.exe /i memroyleak.exe +ust,如图成功后,开启memoryleak.exe程序。

2、利用UMDH创建Heap快照

                

命令格式:umdh -pn:memoryleak.exe -f:snap1.log

程序运行一段时间后或者程序占用内存增加时,然后再次创建heap快照,命令行无差别,snap1.log改为snap2.log或者其他。

3、设置好程序的符号路径,如下图

               

4、设置好后可以开始分析heap前后两个快照的差异

               

分析差异命令:umdh -d snap1.log snap2.log -f:result.txt,生成的result.txt文件在 命令行同目录下,这里是 D:\WinDDK\7600.16385.0\Debuggers 

               

分析完成后查看结果result.txt,红色为umdh定位出来的泄露点,我们在查看源代码:

                  

这样我们就可以修改代码中内存泄露的地方了。

 

B、内存泄露实例分析

两次快照差异文件实例大致如下:

// Debug library initialized ...  D0000-111FFF DBGHELP: Server - private symbols & lines           C:\FunctionServer\Release\Server.pdb  77E70000-77FEFFFF DBGHELP: ntdll - public symbols            c:\mysymbol\wntdll.pdb\B081677DFC724CC4AC53992627BEEA242\wntdll.pdb  。。。。  等等符号加载信息    紧接着是内存泄露信息格式说明   //                                                                           // Each log entry has the following syntax:                                   //                                                                            // + BYTES_DELTA (NEW_BYTES - OLD_BYTES) NEW_COUNT allocs BackTrace TRACEID   // + COUNT_DELTA (NEW_COUNT - OLD_COUNT) BackTrace TRACEID allocations        //     ... stack trace ...                                                    //                                                                            // where:                                                                     //                                                                            //     BYTES_DELTA - increase in bytes between before and after log           //     NEW_BYTES - bytes in after log                                         //     OLD_BYTES - bytes in before log                                        //     COUNT_DELTA - increase in allocations between before and after log     //     NEW_COUNT - number of allocations in after log                         //     OLD_COUNT - number of allocations in before log                        //     TRACEID - decimal index of the stack trace in the trace database       //         (can be used to search for allocation instances in the original    //         UMDH logs).                                                        //                            接着是具体的内存泄露信息    +    47e0 ( 237238 - 232a58)    1f9 allocs  BackTrace8E5CFAC  +       4 (   1f9 -   1f5)  BackTrace8E5CFAC    allocations          ntdll!RtlAllocateHeap+274      Server!malloc+49 (f:\dd\vctools\crt\crtw32\heap\malloc.c, 92)      Server!operator new+1D (f:\dd\vctools\crt\crtw32\heap\new.cpp, 59)      Server!CUi::AddItemText+129 (d:\projects\testtest\common\uilibf, 611)      Server!CUi::AddItemInt+57 (d:\projects\testtest\common\uilibf, 709)      Server!CMainWin::AddOneFunction+1FE (d:\projects\testtest\server\server\, 361)      Server!CTest::FunctionPcInfo+3F9 (d:\projects\testtest\server\server\, 306)      Server!CTest::FunctionReadDispatch+15D (d:\projects\testtest\server\server\, 105)      Server!CTest::FunctionReadCallback+14 (d:\projects\testtest\server\server\, 76)      Server!CWSAAsync::ReadProc+10F (d:\projects\testtest\common\wsaasyncselect, 1336)      Server!CWSAAsync::ReadProcMiddle+12 (d:\projects\testtest\common\wsaasyncselect, 1296)      Server!CWindowsPool::ReadThreadPoolCallback+25 (d:\projects\testtest\common\wsaasyncselect, 332)      ntdll!TppWorkpExecuteCallback+10F      ntdll!TppWorkerThread+572      kernel32!BaseThreadInitThunk+E      ntdll!__RtlUserThreadStart+70      ntdll!_RtlUserThreadStart+1B    。。。。  等等其他内存泄露块信息

根据格式的说明可得到此泄露信息如下:

第一行:+    47e0 ( 237238 - 232a58)    1f9 allocs  BackTrace8E5CFAC

BackTrace8E5CFAC是这个内存块的标记  237238是生成日志文件2时该内存块的大小 232a58是生成日志文件1该内存块的大小  差值47e0 是内存泄露的字节数   1f9是分配内存的次数 (其中47e0 个人理解为申请内存未释放的字节数,因为有可能是释放的时间未到就生成日志文件2 造成只有申请内存 没有释放的情况 所以被判定为内存泄露 关于这点只是个人意见 不一定正确) 。

第二行:+ 4 ( 1f9 - 1f5) BackTrace8E5CFAC allocations

BackTrace8E5CFAC是内存块标记和第一行一样,1f9是生成日志文件2时该内存分配的次数, 1f5是生成日志文件1时该内存分配的次数  差值4是这次该内存块分配的次数。

其他行:是函数调用堆栈,通过分析自己的程序发现,第三行的 Server!CUi::AddItemText+129 (d:\projects\testtest\common\uilibf, 611) 也是内存泄露所在,对应源代码是:pItemLabel = new CLabelUI; 这样基本上就定位到问题所在了

验证一下观点:每一次分配的大小是47e0 /4=4600(十进制),  程序中代码验证了sizeof(CLabelUI)也等于4600, 看来从日志1 到日志2 过程中这个地方new了4次 但是在日志2时 还未释放这些内存 所以造成内存比较时 会定位处该块内存的泄露,至于是否真泄露还是要看程序逻辑,但是既然已定位到该代码 还是要仔细分析一下 看看是逻辑问题 还是真忘了释放内存。

 

B.Windbg手动分析内存泄露

1、全局标志设置,参照上边的设置

2、Windbg调试泄露

开启memoryleak.exe程序,windbg attach到该进程:

             

命令:!heap –s查看当前进程运行的所有堆的情况

然后F5让程序运行一段时间或者内存有明显的增加时再次通过!heap –s查看当前堆的变化,如下图

              

通过对比前后两个堆的变化,发现0x012800000该地址的堆增加的很快而其他堆没什么变化,下面进一步定位

              

命令:!heap –stat –h 查看对应对的状态,发下该堆的内存基本被长度为0x424的块占用,接下来我们在堆中搜索该进程中哪些模块占用0x424长度内存,如下图

              

命令:!heap –flt s 424, 通过搜索程序内存中的堆发现长度为424的堆被大量的占用,进一步查看时谁在使用这个地址

           

找到泄露点了,红色部分的,如果程序对应的符号对应我们可以查看内存泄露点在哪一行

           

 

转载于:https://www.cnblogs.com/renyuan/p/6202998.html

你可能感兴趣的文章
DevOps之持续交付
查看>>
有趣的数学(一)
查看>>
迟来的2013年总结及算法工程师/研究员找工作总结
查看>>
java面向对象中的关键字
查看>>
网络类型IPv4和IPv6什么意思?区别?
查看>>
6周学习计划,攻克JavaScript难关(React/Redux/ES6 etc.)
查看>>
大对象堆及.NET垃圾回收器的改进
查看>>
utf-8引发的页面空白
查看>>
MicroPHP 2.2.0 发布
查看>>
Mysql 语句
查看>>
setState 和 bloc 是仇家
查看>>
jmeter之IP欺骗
查看>>
Ubuntu配置OpenStack 二:配置时间同步NTP和安装数据库Maridb以及问题总结
查看>>
zepto源码--compact、flatten、camelize、dasherize、uniq--学习笔记
查看>>
MyCat:开源分布式数据库中间件
查看>>
递归方法,多维变一维数组
查看>>
#pragma once
查看>>
oracle 触发器
查看>>
通用存储过程(二)
查看>>
CleanAop使用笔记
查看>>