Jesteś tutaj
Tracking heap leaks - gflags and WinDbg - Create user mode stack trace database
This is example how to trace memory leaks using gflags and WinDbg.
I've some application called heaps1.exe which generates 1000000 (0xF4240) memory leaks elements of size 666 Bytes (0x29A).
1. Enable generating user mode stack trace database. You can also make it from GUI.
C:Program FilesDebugging Tools for Windows (x86)>gflags.exe /i heaps1.exe +ust
2. Run application and generate leaks.
3. Attach WinDbg to your process (heaps1.exe).
4. Load necessary symbols pdb.
5. Break into debugger if necessary.
6. And now magic words:
6a. At first check which heaps is leaking the most.
0:001> !heap -s
NtGlobalFlag enables following debugging aids for new heaps:
validate parameters
stack back traces
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
00150000 58000062 1024 76 76 34 2 1 0 0 L
00250000 58001062 64 24 24 11 1 1 0 0 L
00260000 58008060 64 12 12 10 1 1 0 0
00390000 58001062 883776 679796 679796 6 1 1 0 0 L
003d0000 58001062 64 16 16 0 0 1 0 0 L
-----------------------------------------------------------------------------
OK. We see that heap 00390000 has outstanding amoutn of allocations.
6b. Let make statistics of this heap.
0:001> !heap -stat -h 00390000
heap @ 00390000
group-by: TOTSIZE max-display: 20
size #blocks total ( %) (percent of total busy bytes)
29a f4240 - 27b25a80 (99.99)
2012 2 - 4024 (0.00)
1504 1 - 1504 (0.00)
800 2 - 1000 (0.00)
204 3 - 60c (0.00)
214 2 - 428 (0.00)
400 1 - 400 (0.00)
5c 7 - 284 (0.00)
16 19 - 226 (0.00)
220 1 - 220 (0.00)
1fc 1 - 1fc (0.00)
7c 4 - 1f0 (0.00)
1c e - 188 (0.00)
34 6 - 138 (0.00)
98 2 - 130 (0.00)
28 7 - 118 (0.00)
88 2 - 110 (0.00)
80 2 - 100 (0.00)
fe 1 - fe (0.00)
2a 6 - fc (0.00)
OK. Now we see that almost all allocations have size 0x29a (666 Bytes) and there is 0xf4240 allocations of this size.
6c. Let check who allocated these bytes. There will come gigantic flood. You can break it by pressing <ctrl>+<break>
!heap -flt s 29a
0:001> !heap -flt s 29a
_HEAP @ 150000
_HEAP @ 250000
_HEAP @ 260000
_HEAP @ 390000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0039c9f8 0057 0000 [07] 0039ca00 0029a - (busy)
0039ccb0 0057 0057 [07] 0039ccb8 0029a - (busy)
0039cf68 0057 0057 [07] 0039cf70 0029a - (busy)
0039d220 0057 0057 [07] 0039d228 0029a - (busy)
0039d4d8 0057 0057 [07] 0039d4e0 0029a - (busy)
0039d790 0057 0057 [07] 0039d798 0029a - (busy)
0039da48 0057 0057 [07] 0039da50 0029a - (busy)
0039dd00 0057 0057 [07] 0039dd08 0029a - (busy)
0039dfb8 0057 0057 [07] 0039dfc0 0029a - (busy)
0039e270 0057 0057 [07] 0039e278 0029a - (busy)
0039e528 0057 0057 [07] 0039e530 0029a - (busy)
0039e7e0 0057 0057 [07] 0039e7e8 0029a - (busy)
[....]
3190b518 0057 0057 [07] 3190b520 0029a - (busy)
3190b7d0 0057 0057 [07] 3190b7d8 0029a - (busy)
3190ba88 0057 0057 [07] 3190ba90 0029a - (busy)
3190bd40 0058 0057 [07] 3190bd48 0029a - (busy)
3190c000 0057 0058 [07] 3190c008 0029a - (busy)
3190c2b8 0057 0057 [07] 3190c2c0 0029a - (busy)
_HEAP @ 3d0000
6d. And now see callstack of some random allocation.
0:001> !heap -p -a 0039d220
address 0039d220 found in
_HEAP @ 390000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0039d220 0057 0000 [07] 0039d228 0029a - (busy)
Trace: 030b
7c96eed2 ntdll!RtlDebugAllocateHeap+0x000000e1
7c94b394 ntdll!RtlAllocateHeapSlowly+0x00000044
7c918f21 ntdll!RtlAllocateHeap+0x00000e64
78583db8 MSVCR90!malloc+0x00000079
78a34b52 mfc90u!operator new+0x00000033
401450 Heaps1!CHeaps1Dlg::OnBnClickedButton1+0x00000010
78a6d3e9 mfc90u!CCmdTarget::OnCmdMsg+0x00000124
78a5de60 mfc90u!CPropertySheet::OnCmdMsg+0x0000001d
78a3ff73 mfc90u!CWnd::OnCommand+0x00000092
78a3f75b mfc90u!CWnd::OnWndMsg+0x00000066
78a3f6ce mfc90u!CWnd::WindowProc+0x00000024
78a3e2f4 mfc90u!AfxCallWndProc+0x000000a3
78a3e580 mfc90u!AfxWndProc+0x00000037
78a3c247 mfc90u!AfxWndProcBase+0x00000056
7e418734 USER32!InternalCallWinProc+0x00000028
7e418816 USER32!UserCallWinProcCheckWow+0x00000150
7e428ea0 USER32!DispatchClientMessage+0x000000a3
7e428eec USER32!__fnDWORD+0x00000024
7c90e473 ntdll!KiUserCallbackDispatcher+0x00000013
7e4292e3 USER32!SendMessageW+0x0000007f
773f735f COMCTL32!Button_NotifyParent+0x0000003d
773f7441 COMCTL32!Button_ReleaseCapture+0x000000d7
773f9746 COMCTL32!Button_WndProc+0x00000887
7e418734 USER32!InternalCallWinProc+0x00000028
7e418816 USER32!UserCallWinProcCheckWow+0x00000150
7e4189cd USER32!DispatchMessageWorker+0x00000306
7e418a10 USER32!DispatchMessageW+0x0000000f
7e4274ff USER32!IsDialogMessageW+0x00000572
78a6c38d mfc90u!CWnd::IsDialogMessageW+0x00000032
78a42739 mfc90u!CWnd::PreTranslateInput+0x0000002d
78a5b244 mfc90u!CDialog::PreTranslateMessage+0x00000095
78a40974 mfc90u!CWnd::WalkPreTranslateTree+0x00000023
6e. Let see how CHeaps1Dlg::OnBnClickedButton1 looks.
void CauseLeak()
{
int nCount = 1000000;
for (int i = 0; i < nCount; ++i)
{
new char[666];
}
}
void CHeaps1Dlg::OnBnClickedButton1()
{
CauseLeak();
}
7. It is enough to fix bad code.
- Blog
- 223 odsłony

Odpowiedz