缘起:
作为C++程序员,检测内存泄漏是非常痛苦的事情。尤其是看着程序的内存在一直增长,你却无能为力。此时,windbg可以用来检测内存泄漏。
配置windbg:
- 配置symbol文件路径: “SRV*d:\symbols*http://msdl.microsoft.com/download/symbols”.
- 增加测试程序test.exe的pdb 文件到symbol文件路径
- 采用Gflags.exe,增加userstack trace到测试程序leak.exe中。 gflags.exe /i test.exe +ust
开始调试:
1. 打开windbg,点击’attach to process’,挂载上test.exe。
2. 敲入命令>!heap –s
NtGlobalFlag enables following debuggingaids for new heaps:
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
02e90000 08000002 1024 408 1024 31 16 1 0 0 LFH
02e00000 08001002 1088 136 1088 18 4 2 0 0 LFH
04870000 08001002 256 20 256 1 2 1 0 0
00300000 08001002 3136 1308 3136 19 23 3 0 0 LFH
04840000 08001002 64 12 64 3 2 1 0 0
04750000 08001002 256 4 256 1 1 1 0 0
05740000 08001002 256 4 256 0 2 1 0 0
-----------------------------------------------------------------------------
3. 让程序接着运行一段时间。。。
4. 再次输入敲入命令>!heap –s
NtGlobalFlag enables following debuggingaids for new heaps:
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
02e90000 08000002 1024 408 1024 32 16 1 0 0 LFH
02e00000 08001002 1088 136 1088 18 4 2 0 0 LFH
04870000 08001002 256 20 256 1 2 1 0 0
00300000 08001002 3136 1752 3136 14 23 3 0 0 LFH
04840000 08001002 64 12 64 3 2 1 0 0
04750000 08001002 256 4 256 1 1 1 0 0
05740000 08001002 256 4 256 0 2 1 0 0
-----------------------------------------------------------------------------
5. 比较两次heap的分配情况,然后找出堆分配最多的heap,记住堆地址。
6. 输入命令 0:015> !heap -stat -h 00300000
heap@ 00300000
group-by: TOTSIZE max-display: 20
size #blocks total ( %) (percent of total busy bytes)
16a8 32 - 46cd0 (27.90)
800 85 - 42800 (26.20)
14 34dc - 42130 (26.03)
105b8 1 - 105b8 (6.44)
190 32 - 4e20 (1.92)
2012 2 - 4024 (1.58)
4000 1 - 4000 (1.58)
36b0 1 - 36b0 (1.35)
214 14 - 2990 (1.02)
7. 找到分配次数最多的内存堆,记住这个堆的大小,在这个例子中,我们找到分配次数是34dc,堆的大小是14.
8. 此时,输入命令 0:015> !heap -flt s 14
_HEAP @ 2e90000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
02eb33e0 0006 0000 [00] 02eb33f8 00014 - (busy)
mfc90u!CShellWrapper::`vftable'
02eb6ff0 0006 0006 [00] 02eb7008 00014 - (busy)
mfc90u!CShellWrapper::`vftable'
02eb83a8 0006 0006 [00] 02eb83c0 00014 - (busy)
…
9. 查找任意一个分配该大小堆的地址,02eb7008
10. 输入命令0:015> !heap -p -a 02eb7008
address 06aae780 found in
_HEAP @ 300000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
06aae768 0006 0000 [00] 06aae780 00014 - (busy)
7719ddbd ntdll!RtlAllocateHeap+0x00000274
747c3a58 MSVCR90!malloc+0x00000079
460879 test!CUDPThread::Run+0x00000689
4601dc test!CUDPThread::Main+0x0000003c
74783433 MSVCR90!_callthreadstartex+0x0000001b
747834c7 MSVCR90!_threadstartex+0x00000069
11. 至此,我们可以定位程序中memory leak的函数了。
Issues:
1. Error: Symbol can not be found.
0:015> .reload /f 强制加载module
Reloading current modules
......
…
0:015> lm 查看module加载情况
start end module name
741e0000 741e5000 wshtcpip (export symbols) C:\Windows\System32\wshtcpip.dll
741f0000 7422c000 mswsock (export symbols) C:\Windows\system32\mswsock.dll
74240000 74253000 dwmapi (export symbols) C:\Windows\system32\dwmapi.dll
74260000 742e0000 UxTheme (export symbols) C:\Windows\system32\UxTheme.dll
742e0000 742e9000 VERSION (export symbols) C:\Windows\system32\VERSION.dll
2. Heap – Invalid type information
0:015> !heap -s
*************************************************************************
*** Either you specified an unqualified symbol, or your debugger ***
*** doesn't have full symbol information. Unqualified symbol ***
*** resolution is turned off by default. Please either specify a ***
*** fully qualified symbol module!symbolname, or enable resolution ***
*** of unqualified symbols by typing ".symopt- 100". Notethat ***
*** enabling unqualified symbol resolution with network symbol ***
*** server shares in the symbol path may cause the debugger to ***
*** appear to hang for long periods of time when an incorrect ***
*** symbol name is typed or the network symbol server is down. ***
*** For some commands to work properly, your symbol path ***
*** must point to .pdb files that have full type information. ***
*** Certain .pdb files (such as the public OS symbols) do not ***
*** contain the required information. Contact the group that ***
*** provided you with these symbols if you need this command to ***
*** Type referenced: ntdll!_HEAP_ENTRY ***
*************************************************************************
Invalid type information
解决方法:
0:015> .symfix
0:015> .reload
Reloading current modules
.......................................