如何定位内存泄漏( 二 )

显示如下
0:000> !heap -sHEAPEXT: Unable to read ntdll!RtlpDisableHeapLookasideHeap Flags Reserv Commit Virt Free List UCR Virt Lock Fast(k) (k) (k) (k) length blocks cont. heap-----------------------------------------------------------------------------006f0000 00000002 1246976 1241928 1246976 982 236 81 0 a LFH00190000 00001002 3136 1564 3136 390 7 3 0 0 LFHExternal fragmentation 24 % (7 free blocks)00110000 00001002 256 4 256 1 1 1 0 002050000 00001002 256 176 256 1 18 1 0 0 LFH02240000 00001002 256 4 256 2 1 1 0 0006a0000 00001002 64 12 64 4 2 1 0 0044f0000 00001002 256 216 256 7 4 1 0 0 LFH119d0000 00001002 7424 5820 7424 134 133 4 0 c8 LFH14290000 00001003 256 4 256 2 1 1 0 bad141d0000 00001003 256 4 256 2 1 1 0 bad17f20000 00001003 256 4 256 2 1 1 0 bad19030000 00001003 256 4 256 2 1 1 0 bad191b0000 00001003 256 4 256 2 1 1 0 bad19380000 00001003 256 4 256 2 1 1 0 bad19300000 00001003 256 4 256 2 1 1 0 bad155f0000 00001003 256 4 256 2 1 1 0 bad-----------------------------------------------------------------------------通过观察,我们知道了是006f0000堆块占用了大量内存
HEAPEXT: Unable to read ntdll!RtlpDisableHeapLookasideHeap Flags Reserv Commit Virt Free List UCR Virt Lock Fast(k) (k) (k) (k) length blocks cont. heap-----------------------------------------------------------------------------006f0000 00000002 1246976 1241928 1246976 982 236 81 0 a LFH查看堆块内存百分比内存持续上涨可能是某块固定大小内存被重复申请,所以统计下该堆块中各个内存大小的分配次数
!heap -stat -h 006f0000查找堆中各个内存大小占用的百分比
0:000> !heap -stat -h 006f0000unable to resolve ntdll!RtlpStackTraceDataBaseheap @ 006f0000group-by: TOTSIZE max-display: 20size #blocks total ( %) (percent of total busy bytes)14 23acbbe - 2c97ead8 (92.78)a4 2ba0c - 1bf2fb0 (3.63)1000 8f5 - 8f5000 (1.16)1a4 3b9c - 61cbf0 (0.79)20c 15fb - 2cfdc4 (0.37)25 b77d - 1a8511 (0.22)64 3ba0 - 174a80 (0.19)24 75ae - 108c78 (0.13)11c e4a - fda18 (0.13)84c 164 - b89b0 (0.09)400 172 - 5c800 (0.05)234 265 - 54684 (0.04)1c 2c2e - 4d508 (0.04)1c0 287 - 46c40 (0.04)c00 4b - 38400 (0.03)20 1a12 - 34240 (0.03)3bc ce - 30148 (0.02)50 8da - 2c420 (0.02)800 4c - 26000 (0.02)2ba d2 - 23c94 (0.02)size #blocks total ( %) (percent of total busy bytes)14 23acbbe - 2c97ead8 (92.78)TOP 20 中显示,最多的一个大小为 0x014 的分配次数为 0x23acbbe 次,总共大概有700M左右 。基本接近内存泄漏的总数 。
所以这里得出几个结论:

  • 每次内存泄漏的大小是20字节 。
  • 总共分配了0x23acbbe次,运行了90天,也就是每小时17318次/小时
定位内存来源找到了大量的内存是0x014字节大小的,但是根据这个条件我们也找不到具体的代码啊?下面是几个思路
  • 根据大小
根据内存大小(0x14)去代码中查找大小为(0x14)的类、结构体、宏等等相关代码,然后找到原因 。有几个问题:
1)、进程包含了很多其他组的dll,有的我没代码权限,无法遍历
2)、结构体、类太多了,人眼遍历太难了(针对这个问题我后来开发了一个工具,通过pdb文件可以找到程序中指定大小的所有结构体和类,后续章节讲解)
  • 内存内容
显示所有大小为(0x14)内存的地址,看它的地址内容有没有什么特点,比如是否有特殊的字符串、固定的二进制头??? 显示所有分配大小为 0x14的内存
命令!heap -flt s 140:000> !heap -flt s 14unable to resolve ntdll!RtlpStackTraceDataBase_HEAP @ 6f0000HEAP_ENTRY Size Prev Flags UserPtr UserSize - state0071c038 0004 0000 [00] 0071c040 00014 - (busy)0071c2e8 0004 0004 [00] 0071c2f0 00014 - (busy)0071e498 0004 0004 [00] 0071e4a0 00014 - (busy)0071e4f8 0004 0004 [00] 0071e500 00014 - (busy)0071e518 0004 0004 [00] 0071e520 00014 - (busy)0071e5f8 0004 0004 [00] 0071e600 00014 - (busy)0071e638 0004 0004 [00] 0071e640 00014 - (busy)0071e658 0004 0004 [00] 0071e660 00014 - (busy)0071e798 0004 0004 [00] 0071e7a0 00014 - (busy)007374f0 0004 0004 [00] 007374f8 00014 - (busy)00737510 0004 0004 [00] 00737518 00014 - (busy)00737530 0004 0004 [00] 00737538 00014 - (busy)00737550 0004 0004 [00] 00737558 00014 - (busy)00737570 0004 0004 [00] 00737578 00014 - (busy)00737590 0004 0004 [00] 00737598 00014 - (busy)007375b0 0004 0004 [00] 007375b8 00014 - (busy)007375d0 0004 0004 [00] 007375d8 00014 - (busy)007375f0 0004 0004 [00] 007375f8 00014 - (busy)00737610 0004 0004 [00] 00737618 00014 - (busy)00737630 0004 0004 [00] 00737638 00014 - (busy)00737650 0004 0004 [00] 00737658 00014 - (busy)00737670 0004 0004 [00] 00737678 00014 - (busy)00737690 0004 0004 [00] 00737698 00014 - (busy)............................随机抽查几个地址,看下地址内存,都是00 00 00 00 00
大都是这样的值,实在是看不出规律 。


推荐阅读