首页 > 其他 > 详细

内存泄漏排查方法

时间:2020-07-30 14:59:20      阅读:86      评论:0      收藏:0      [点我收藏+]

1.问题描述:

使用Windows任务管理器发现某一进程内存使用量特别巨大,且随着时间增长内存使用量一直在增加。 

2.排查步骤:

2.1 静态分析

1. 使用WinDbg打开可能发生内存泄漏的程序DUMP文件。 

2. 使用 !heap –s 命令将本进程中所有堆的统计信息转储出来。

 技术分享图片

 

 

其中:-s开关将给出进程中每个堆的基本信息。Heap列表示的是堆的地址(句柄),Reserv指定堆的保留内存数量,Commit指定堆的已提交内存数量,Virt指定堆的虚拟内存数量。

从图中可以看出,表示为02d90000的堆消耗了最大的内存,这个堆的保留内存量为583104KB,已提交的内存量为581596KB。由此可见,这个堆很可疑,进行第3步分析。

 

3. 使用 !heap –stat –h [heap] 命令获取可疑堆的统计信息。

 技术分享图片

 

          可知,在句柄为02d90000的可疑堆中,比较可疑的分配操作有图中标识的那些。比如,第一行表示大小2178B的内存分配了47c4次,占该堆内存分配总量的28.45%,第二行大小2082B的内存也分配了47c4次,占该堆分配总量的27.64%,需要重点分析这些size的分配操作。

 

4. 接下来,通过!heap –a 命令把可疑堆的信息详尽的转储出来。由于这个操作最终生成的信息较为庞大,为方便分析,可将其转储到一个日志文件中(先执行命令 .logopen  <filename>,再执行 !heap –a [heap],最后执行 .logclose 来关闭这个日志文件,如下图所示)。

 技术分享图片

 

 技术分享图片

 

 图中将 !heap –a 02d90000 命令的结果转储到了 heap.txt 文件中,该文件在与 WinDbg.exe同级的目录下,稍后的分析需要用到此文件。

 

 5. 紧接着,分析下到底在哪个栈回溯中执行了这个内存分配操作,如果能得到这个信息,那么就能准确的找出代码正在执行什么操作以及它正在分配什么内存。因此我们需要通过 !heap –p –a [address] 命令获知栈回溯,其中-p告知!heap命令页堆被启用了,而-a用来指定一个地址来查看栈回溯。那么,到底是哪些地址可疑呢?因为第3步中已经分析出可疑分配大小,我们可以根据此信息在上一步转储的heap.txt中搜索符合指定大小的分配情况。

 技术分享图片

 

 技术分享图片

 

 可知在地址 139c3ad8 处分配了2178B 大小的空间,使用 !heap –p –a 进行分析:

 技术分享图片

 

 如果像上图一样得到的堆栈中缺乏有效信息,则使用 !heap –l 命令来检测内存中处于活跃状态却没有被引用的内存,详见第6步。或者使用动态分析技术,见下面的第2部分的分析。

 

6. 使用 !heap –l 命令检测在进程中处于活跃状态但却没有被引用的内存,该命令采用了一种垃圾收集算法来进行检测。注意:此命令运行时间相当长,且输出内容相当多,请采用第4步的方法将内存的内容转储到日志文件中,之后对文件内容进行分析。

下面是该文件的部分内容,

 技术分享图片

 

 技术分享图片

 

 尝试用其中一个栈回溯记录搜索一下,(见下图)发现竟然有744个类似的分配操作,不得不怀疑该处存在着内存泄漏

 技术分享图片

 

 

接下来,可以使用Windbg的ln命令查看此处在代码中的什么地方,

 技术分享图片

 

 发现指示的是代码的299行,分析此处附近的源代码,确实可疑,

 技术分享图片

 

 此处tempVal的内存空间并没有释放。

 其它类似的疑似泄漏点分析方法相同,不再赘述

  

2.2 动态分析

2.2.1使用WinDbg附加进程进行分析。

1. 使用WinDbg附加到可疑进程。

2. 使用gflags.exe(该工具与windbg.exe同级目录下)为目标进程启用页堆,方法是运行命令:gflags.exe /i xxx.exe +hpa。

 技术分享图片

 

 3. 接着使用 !heap -stat -h 0 命令列出本进程中所有堆的使用状态。

 技术分享图片

 

 从中可发现 00690000 这个堆中的分配行为非常可疑,最大的每次分配0x100000字节大小的内存,总共分配了e9次,占该堆分配总量的100.00%,非常之可疑。

 4. 接下来使用 !heap –flt s Size 命令列出所有大小 为 0x100000 字节大小的内存。

 技术分享图片

 

 从图可知,找到了很多这样符合要求的分配,也是在上述找到的堆上的。

然后我们任选一个地址,使用命令 !heap –p –a [address] 获取分配操作的栈回溯,最后使用 ln 命令就可找到程序中内存泄漏点在哪儿了

 技术分享图片

 

 

2.2.2 使用UMDH进行分析

1. 启动记录内存分配的栈回溯,即使用 gflags 工具并为目标程序启用 “Create user mode stack trace database”(创建用户态栈回溯数据库)。

命令行方式:

 技术分享图片

 

 图形界面方式:

 技术分享图片技术分享图片

 

 

 

 

2. 设置 _NT_SYMBOL_PATH 环境变量为 符号路径,比如:srv*C:\mssymbols*http://msdl.microsoft.com/download/symbols;C:\Users\zhouqingshan.INTRA\Desktop\TempDebug

  技术分享图片

 

  

4. 记录疑似泄漏程序第一次的运行状态,UMDH.exe –p:<PID>  >  <finename>,比如:UMDH.exe  -p:12264  > firstsnap.txt

 技术分享图片

 

 5. 等一段时间,再次记录程序的运行状态,比如:UMDH.exe  -p:12264  > secondsnap.txt

 技术分享图片

 

 6. 比较两次状态的差异,UMDH.exe  -v  firstsnap.txt secondsnap.txt  > snapdiff.txt

 技术分享图片

 

 在生成了文件 snapdiff.txt 后,通过分析这个文件可以找出程序中内存泄漏的源头。

 技术分享图片

 

 文件的第一部分包含了关于文件格式的一些说明。UMDH能够根据内存分配的大小和数量对栈回溯进行排序。内存分配数量最大和最多的栈回溯被放在文件开头。上面文件内容截图中给出的是第一个栈回溯。

 技术分享图片

 

 这一行告诉我们,在栈回溯中执行的内存分配操作使内存使用量增长了 5400000 个字节,还告诉我们这个栈回溯被调用了 152 次,也就是执行了152次分配操作。同样的栈回溯被调用了152次,这是非常可疑的,之后可结合代码重点分析,比如下图中指示的451行。

 

内存泄漏排查方法

原文:https://www.cnblogs.com/bashen2015/p/13403267.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!