Борьба с утечками памяти.
Автор: Анатолий Белов
Всем известна проблема утечки памяти. Порой поиски утечки памяти могут сильно затормозить разработку програмного продукта. Человечество изобрело множество способов обнаружить эту утечку. Например, можно использовать такое могучее и дорогое ПО как BoundChecker, но есть другой способ, в чём-то более простой и удобный. Это прегрузка операторов new и delete.
Сразу оговорюсь - такой способ лучше всего подходит для кода, написанного в объектно-ориентированном стиле.
Теперь конкретней. Перегрузка операторов выглядит следующим образом:
void *operator new(size_t size); void operator delete( void *pPointer);
Перегрузив эти операторы внутри класса, мы можем получить статистику динамического выделения памяти под класс, а именно это нам и надо. В качестве примера реализации этих операторов приведу следующий код:
void *operator new(size_t size) { gMemCount++; gMemSizes += size; ofstream out( "memtrace.txt", ios::app); out<<"new: id="<<gmemid<<", size="<<size<<", num blocks=" <<gMemCount<<", all sizes="<<gMemSizes<<'\n'; out.close( ); unsigned int *p = ( unsigned int*)malloc( size+sizeof( unsigned int)); *p = gmemid++; return p+1; } void operator delete( void *pPointer) { gMemCount--; unsigned int *p = ( unsigned int *)pPointer; p--; ofstream out( "memtrace.txt", ios::app); out<<" delete: id="<<*p<<", num blocks="<<gMemCount<<'\n'; out.close( ); free( p); }
как можно видеть, выделяется памяти больше чем надо. В начало выделенного блока записывается отладочная информация. В данном случае это идентификационный номер выделяемого блока. В результате выполнения в файле по этому идентификатору можно будет найти те блоки, которые не освободились, а ещё увидеть, сколько блоков не освободилось (gMemCount), что тоже важно. Ещё в файле можно увидеть сколько памяти всего выделяется под класс и его детей в процессе работы (gMemSizes). Так можно посмотреть сколько памяти не освободилось. Последняя цифра обычно заставляет задуматься. В общем, перегрузка операторов - полезная вещь.
Дальше. Если вы нашли идентификатор не оcвободившегося блока, то можно воспользоваться услугами отладчика. Для этого берём и вставляем в new строки:
if(gMemCount == num) { gMemCount = gMemCount; // ставим здесь breakpoint }
где num - номер требуемого блока. А дальше - трассируем, смотрим, кто выделяет память, а дальше.. а дальше дело техники.
Что ещё можно сказать. Можно выделить эти операторы в отдельный класс, и потом наследовать от этого класса. Можно сделать глобальную перегрузку этих операторов, тоже будет повод задуматься над бренностью жизни. Но врачи не советуют глобально перегружать их.
28 июля 2003