Как отловить утечки памяти MS Visual C++

2010-06-13 papirosnik Программирование

Что такое "утечки памяти" (memory leaks) и чем чревато их наличие пожалуй объяснять не стану. Просто попытаюсь рассказать, как их улавливать стандартными средствами среды Microsoft Visual C++. Версия вроде принципиального значения не имеет, т.к. пользуюсь этим средством начиная с MS VC 2003 и до сих пор (MS VC 2010) без каких либо изменений. Обычные механизмы  отлова утечек немало освещены в Интернете, в частности довольно детально описаны на MSDN. Здесь же хочу показать, как ловить утечки не всей программы вообще, а отдельных её фрагментов, что позволяет локализвать проблемные места  и разобраться с ними.Итак, для включения механизма отлова утечек достаточно подключить стандартную библиотеку  crtdbg.h и вызвать одну функцию, включающую режим автоматического детектирования. Чтобы исключить её из финальной версии програмы, подключать её будем только если программа компилируется в режиме отладки.

#ifdef _DEBUG
#include 
#endif

Справделивости ради надо отметить, что по-моему эта библиотека и так настроена для использования только в режиме отладки (Debug mode) , поэтому возможно её не надо включать в блок условной компиляции (#ifdef.. #endif). Ну да ладно, не будучи уверенными на 100% в этом,  пару строк  не помешают.

Далее, в самом начале программы (обычно в начале функции WinMain или main)  пишем следующий код:

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

Здесь мы установили режим _CRTDBG_ALLOC_MEM_DF (проверять корректность выделения/высвобождения памяти) и _CRTDBG_LEAK_CHECK_DF (выводить диагностические сообщения при выходе из программы). Установка второго флага освобождает нас от необходимости самостоятельно выводить информацию о неосвобожденных блоках. Библиотека crtdbg cделает это за нас, независимо от того, в каком месте и по какой причине программа завершается. Более подробно об остальных флагах (более редко используемых) можно узнать из MSDN. От себя хочу только добаить, что существует ещё олин довольно распространённый флаг — _CRTDBG_CHECK_ALWAYS_DF (вызывать проверку при каждом размещении/высвобождении) блока, но его использование при интенсивном динамическом распределении памяти существенно замедляет программу в режиме отладки. В некоторых случаях мои программы работали в 7-10 раз медленнее!

Это всё то, что описано многократно и практически общеизвестно. Есть механизм переопределения функций new и delete, который позволяет показать, в каком файле и в какой строке произошла утечка. Как задействовать это механизм и какие при этом возникают нюансы будет раскрыто в отдельной статье. Здесь же зададимся целью узнать — а не утекает ли память в каком-либо блоке программы? Например, у нас есть функция, которая интенсивно распределяет/высвобождает память, и нам надо проконтролировать, делает ли она это корректно.

Для это вначале функции объявим три переменных типа _CrtMemState (описан в crtdbg.h). Затем сразу же вызываем функцию _CrtMemCheckpoint( &s1 ). Здесь мы получили снимок динамической памяти на момент запсука функции. В самом конце, перед точкой выхода, мы ещё раз вызываем эту функцию, но снимок памяти теперь помещаем в переменную s2:_CrtMemCheckpoint( &s2 ); Затем просто сравниваем эти два снимка при помощи функции _CrtMemDifference и, если они не равны, то выводим разницу функцией _CrtMemDumpStatistics. Пример кода представлен ниже:

 

#include 
...
void DoSomething()
{
    _CrtMemState s1, s2, s3;
    // Здесь находится весь код функции, у кторой
    // мы хотим проверить корректность
    // выделения/высвобождения памяти.
    . . .
    _CrtMemCheckpoint( &s2 );
    if ( _CrtMemDifference( &s3, &s1, &s2) )
            _CrtMemDumpStatistics( &s3 );
}

 

Здесь разница снимков s1 и s2 помещается в переменую s3. И елси эта разница имеет место, в окне Output мы получим примерно такую информацию:

0 bytes in 0 Free Blocks.
2808 bytes in 35 Normal Blocks.
101 bytes in 6 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 27053 bytes.
Total allocations: 86637 bytes.

Это говорит о том, что в нашей функции утекло  2808 байт памяти. Записи относительно CRT Blocks являются внутренними для crtdbg, и то, что там детектируется утечка — не ваша вина. В релизной версии этого не будет, так что можно на них не обращать внимания.

 

crtdbg, утечки памяти,

3 комментария to “Как отловить утечки памяти MS Visual C++”


Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Powered by WordPress. Designed by elogi.