缘起

作为C++程序员,检测内存泄漏是非常痛苦的事情。尤其是看着程序的内存在一直增长,你却无能为力。此时,windbg可以用来检测内存泄漏。


配置windbg

 

  1.  配置symbol文件路径: “SRV*d:\symbols*http://msdl.microsoft.com/download/symbols”.
  2.  增加测试程序test.exe的pdb 文件到symbol文件路径
  3.  采用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

.......................................