参考:http://hi.baidu.com/xingxing/item/f834ffeae93fcf2d5b7cfb9a
有一个程序运行了一段时间后,内存占用呈线性增长,而且一直不降下来。
在 windbg 中对其动态调试,以确定原因。
先查看初始的堆状态:
0:007> !heap -s
NtGlobalFlag enables following debugging aids for new heaps:
stack back traces
LFH Key : 0x34d21697
Termination on corruption : DISABLED
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
00230000 08000002 1024 544 1024 17 14 1 0 0 LFH
00010000 08008000 64 4 64 2 1 1 0 0
01a30000 08001002 1088 80 1088 4 3 2 0 0 LFH
02d10000 08001002 1088 932 1088 98 38 2 0 0 LFH
02ca0000 08001002 256 60 256 1 4 1 0 0 LFH
02f10000 08001002 256 172 256 125 3 1 0 0
04340000 08001002 64 4 64 2 1 1 0 0
02e60000 08001002 64 4 64 2 1 1 0 0
044c0000 08011002 256 4 256 1 2 1 0 0
04690000 08001002 256 4 256 1 2 1 0 0
-----------------------------------------------------------------------------
0:007> g
(504.c9c): Break instruction exception - code 80000003 (first chance)
eax=7ffd7000 ebx=00000000 ecx=00000000 edx=7709f125 esi=00000000 edi=00000000
eip=770340f0 esp=0317ff5c ebp=0317ff88 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!DbgBreakPoint:
770340f0 cc int 3
运行了一小段时间后,再看一下,和之前的对比,发现某个堆增长明显:
0:007> !heap -s
NtGlobalFlag enables following debugging aids for new heaps:
stack back traces
LFH Key : 0x34d21697
Termination on corruption : DISABLED
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
00230000 08000002 2048 1868 2048 17 17 2 0 0 LFH
00010000 08008000 64 4 64 2 1 1 0 0
01a30000 08001002 1088 80 1088 4 3 2 0 0 LFH
02d10000 08001002 1088 980 1088 147 40 2 0 0 LFH
02ca0000 08001002 256 60 256 1 4 1 0 0 LFH
02f10000 08001002 256 172 256 125 3 1 0 0
04340000 08001002 64 4 64 2 1 1 0 0
02e60000 08001002 64 4 64 2 1 1 0 0
044c0000 08011002 256 4 256 1 2 1 0 0
04690000 08001002 256 4 256 1 2 1 0 0
-----------------------------------------------------------------------------
统计一下这个堆里的内存分配情况,发现 1000 字节的内存分配占了 86.97%,目标就锁定它了。
0:007> !heap -stat -h 00230000
heap @ 00230000
group-by: TOTSIZE max-display: 20
size #blocks total ( %) (percent of total busy bytes)
1000 158 - 158000 (86.97)
494 16 - 64b8 (1.59)
20 2fd - 5fa0 (1.51)
34 161 - 47b4 (1.13)
3980 1 - 3980 (0.91)
d0 30 - 2700 (0.62)
1034 2 - 2068 (0.51)
78 39 - 1ab8 (0.42)
c88 2 - 1910 (0.40)
10 131 - 1310 (0.30)
11f8 1 - 11f8 (0.28)
208 7 - e38 (0.22)
248 6 - db0 (0.22)
58 23 - c08 (0.19)
400 3 - c00 (0.19)
80 15 - a80 (0.17)
a28 1 - a28 (0.16)
960 1 - 960 (0.15)
928 1 - 928 (0.14)
22 39 - 792 (0.12)
看一下都是哪些堆申请的:
0:007> !heap -flt s 1000
_HEAP @ 230000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0027b810 0203 0000 [00] 0027b828 01000 - (busy)
0027c900 0203 0203 [00] 0027c918 01000 - (busy)
00285670 0203 0203 [00] 00285688 01000 - (busy)
00286688 0203 0203 [00] 002866a0 01000 - (busy)
002876a0 0203 0203 [00] 002876b8 01000 - (busy)
002886b8 0203 0203 [00] 002886d0 01000 - (busy)
002896d0 0203 0203 [00] 002896e8 01000 - (busy)
0028a6e8 0203 0203 [00] 0028a700 01000 - (busy)
0028bf10 0203 0203 [00] 0028bf28 01000 - (busy)
0028cf28 0203 0203 [00] 0028cf40 01000 - (busy)
0028df40 0203 0203 [00] 0028df58 01000 - (busy)
....
....
....
_HEAP @ 10000
_HEAP @ 1a30000
_HEAP @ 2d10000
_HEAP @ 2ca0000
_HEAP @ 2f10000
_HEAP @ 4340000
_HEAP @ 2e60000
_HEAP @ 44c0000
_HEAP @ 4690000
随便挑几个地址看一下调用栈:
0:007> !heap -p -a 0303aec0
address 0303aec0 found in
_HEAP @ 230000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0303aec0 0221 0000 [00] 0303aed8 01000 - (busy)
7707dd6c ntdll!RtlAllocateHeap+0x00000274
7541f947 KERNELBASE!FindNextFileW+0x00000090
...
...
771a3c45 kernel32!BaseThreadInitThunk+0x0000000e
770637f5 ntdll!__RtlUserThreadStart+0x00000070
770637c8 ntdll!_RtlUserThreadStart+0x0000001b
再结合源代码,确定是 FindNextFileW 遍历文件完成之后,没有调用 FindClose 关闭句柄,导致资源没有被释放。
在使用上面的方法调试之前,要先打开 Create user mode stack trace database
0:004> !gflag +ust
Current NtGlobalFlag contents: 0x00001000
ust - Create user mode stack trace database