понедельник, 2 марта 2009 г.

Антикризисное средство поиска утечек памяти

При современном подходе к программированию на языке C++ довольно просто избежать всех проблем связанных с утечками памяти. Аллокаторы, в общем, неплохо заботятся о пямяти — тут вам и автоудаление, и слежение за фрагментацией (например, boost::pool_alloc), и прочие радости. Однако, иногда попадается код, где выделение памяти организовано плохо(с ошибками, а значит плохо).

В составе Debugging Tools for Windows присутствует утилита umdh (user-mode dump heap). Пользоваться этой тулзой довольно просто. Сначала делается пара дампов состояния памяти с помощью команд:
umdh.exe -p:3804 -f:p:\result1.log
umdh.exe -p:3804 -f:p:\result2.log
, где 3804 — идентификатор процесса (его можно посмотреть в task manager). Потом можно сравнить эти два состояния следующей командой:
umdh.exe p:\result1.log p:\result2.log -f:p:\final.log
Самое интересное начинается при сравнении. umdh умеет подгружать pdb файлы из путей, определенный переменной _NT_SYMBOL_PATH (как и все прочие тулзы в Debugging Tools).

Результат сравнения позволяет посмотреть стек и количество выделенных байт. Выглядит это так:
// Each log entry has the following syntax:                                 
//                                                                          
// + BYTES_DELTA (NEW_BYTES - OLD_BYTES) NEW_COUNT allocs BackTrace TRACEID 
// + COUNT_DELTA (NEW_COUNT - OLD_COUNT) BackTrace TRACEID allocations      
//     ... stack trace ...                                                  
//                                                                          
// where:                                                                   
//                                                                          
//     BYTES_DELTA - increase in bytes between before and after log         
//     NEW_BYTES - bytes in after log                                       
//     OLD_BYTES - bytes in before log                                      
//     COUNT_DELTA - increase in allocations between before and after log   
//     NEW_COUNT - number of allocations in after log                       
//     OLD_COUNT - number of allocations in before log                      
//     TRACEID - decimal index of the stack trace in the trace database     
//         (can be used to search for allocation instances in the original  
//         UMDH logs).                                                      

+     2f0 (   2f0 -     0)      1 allocs BackTraceA39
+       1 (     1 -     0) BackTraceA39 allocations

ntdll!RtlpAllocateHeap+000000C6
ntdll!RtlAllocateHeap+000001E3
gdiplus!GpMalloc+00000016
gdiplus!GdipCreateBitmapFromGdiDib+00000090
DkClient2!Gdiplus::Bitmap::Bitmap+00000069 (c:\program files\microsoft sdks\windows\v6.0a\include\gdiplusbitmap.h, 653)
DkClient2!Gdiplus::Bitmap::FromBITMAPINFO+00000064 (c:\program files\microsoft sdks\windows\v6.0a\include\gdiplusbitmap.h, 736)
DkClient2!CAlarmZone::OnFrame+00000095 (p:\svn\orwell\head\dkclient\trunk\alarmzone.cpp, 361)

Total decrease ==   25ea requested +    41e overhead =   2a08

По такому отчету уже вполне можно определить место утечки и разбираться дальше. Конечно, есть дорогие средства с красивым интерфейсом вроде BoundsChecker'a. Однако, не все могут позволить себе покупку таких средств, а umdh совершенно бесплатна.

Более подробно по этой теме можно почитать на сайте автора программы. Ах, да... забыл написать, что сделали эту тулзу в небольшой компании из Редмонда. Теперь компания уже немаленькая, однако, программке красивый интерфейс не прикрутили — это, может, и к лучшему... а то стоила бы как BoundsChecker...

Комментировать в ВКонтакте