Войти
Подсказки

Борьба с утечками памяти.

Автор:

Всем известна проблема утечки памяти. Порой поиски утечки памяти могут сильно затормозить разработку програмного продукта. Человечество изобрело множество способов обнаружить эту утечку. Например, можно использовать такое могучее и дорогое ПО как 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