Ошибка: Failed to parse the Currency Converter XML document.
$2 893.01


Ошибка: Failed to parse the Currency Converter XML document.
$12 054.94


Ошибка: Failed to parse the Currency Converter XML document.
$1 025.07


Как обнаружить утечку памяти

При разработке больших приложений, оперирующих большими объемами информации на первое место при отладке встает проблема обнаружения неправильного распределения памяти. Суть проблемы состоит в том, что если мы выделили участок памяти, а затем освободили не весь выделенный объем, то образуются блоки памяти, которые помечены как занятые, но на самом деле они не используются. При длительной работе программы такие блоки могут накапливаться, приводя к значительному расходу памяти.

Как обнаружить утечку памяти
Введение

При разработке больших приложений, оперирующих большими объемами информации на первое место при отладке встает проблема обнаружения неправильного распределения памяти. Суть проблемы состоит в том, что если мы выделили участок памяти, а затем освободили не весь выделенный объем, то образуются блоки памяти, которые помечены как занятые, но на самом деле они не используются. При длительной работе программы такие блоки могут накапливаться, приводя к значительному расходу памяти.


Для обнаружения подобных ошибок создано специализированное программное обеспечение (типа BoundsChecker от Numega), однако чаще бывает удобнее встроить механизм обнаружения утечки в свои проекты. Поэтому метод должен быть простым, и в то же время как можно более универсальным. Кроме того, не хотелось бы переписывать годами накопленные мегабайты кода, написанного и отлаженного задолго до того, как вам пришло в голову оградить себя от ошибок. Так что к списку требований добавляется стандартизация, т.е. нужно каким-то образом встроить защиту от ошибок в стандартный код.


Предлагаемое решение основывается на перегрузке стандартных операторов распределения памяти new и delete. Причем перегружать мы будем глобальные операторы new|delete, т.к. переписать эти операторы для каждого разработанного ранее класса было бы очень трудоемким процессом. Т.о. после перегрузки нам нужно будет только отследить распределение памяти и, соответственно, освобождение ее в момент завершения программы. Все несоответствия — ошибка.

Реализация

Проект написан на Visual C++, но переписать его на любой другой диалект С++ не будет слишком сложной задачей. Во-первых, нужно переопределить стандартные операторы new и delete так, чтобы это работало во всех проектах. Поэтому в stdafx.h добавляем следующий фрагмент:

#ifdef _DEBUG
inline void * __cdecl operator new(unsigned int size,
                                   const char *file, int line)
{
};

inline void __cdecl operator delete(void *p)
{
};
#endif

Как видите, переопределение операторов происходит в блоке #ifdef/#endif. Это ограждает наш код от влияния на релиз компилируемой программы. Вы, наверное, заметили, что теперь оператор new имеет три параметра вместо одного. Два дополнительных параметра содержат имя файла и номер строки, в которой выделяется память. Это удобно для обнаружения конкретного места, где происходит ошибка. Однако код наших проектов по-прежнему ссылается на оператор new, принимающий один параметр. Для исправления этого несоответствия нужно добавиить следующий фрагмент

#ifdef _DEBUG
#define DEBUG_NEW new(__FILE__, __LINE__)
#else
#define DEBUG_NEW new
#endif
#define new DEBUG_NEW

Теперь все наши операторы new будут вызываться с тремя параметрами, причем недостающие параметры подставит препроцессор. Конечно, пустые переопределенные функции ни в чем нам не помогут, так что давайте добавим в них какой-нибудь код:

#ifdef _DEBUG
inline void * __cdecl operator new(unsigned int size,
                                   const char *file, int line) {
void *ptr = (void *)malloc(size);
AddTrack((DWORD)ptr, size, file, line);
return(ptr);
};
inline void __cdecl operator delete(void *p) {
RemoveTrack((DWORD)p);
free(p);
};
#endif

Для полноты картины нужно переопределить операторы new[] и delete[], однако никаких существенных отличий здесь нет — творите!

Последний штрих — пишем функции AddTrack() и RemoveTrack(). Для создания списка используемых блоков памяти будем использовать стандартные средства STL:

typedef struct {
    DWORD address;
    DWORDsize;
    charfile[64];
    DWORDline;
} ALLOC_INFO;

typedef list AllocList;

AllocList *allocList;

void AddTrack(DWORD addr,  DWORD asize,  const char *fname, DWORD lnum)
{
    ALLOC_INFO *info;

    if(!allocList) {
      allocList = new(AllocList);
    }

    info = new(ALLOC_INFO);
    info->address = addr;
    strncpy(info->file, fname, 63);
    info->line = lnum;
    info->size = asize;
    allocList->insert(allocList->begin(), info);
};

void RemoveTrack(DWORD addr)
{
    AllocList::iterator i;

    if(!allocList)
      return;
    for(i = allocList->begin(); i != allocList->end(); i++)
    {
      if((*i)->address == addr)
      {
      allocList->remove((*i));
      break;
      }
    }
};

Перед самым завершением программы наш список allocList содержит ссылки на блоки памяти, котороые не были освобождены. Все, что нужно сделать — вывести эту информацию куда-нибудь. В нашем проекте мы выведем список неосвобожденных участков памяти в окно вывода отладочных сообщений Visual C++:

void DumpUnfreed() {
AllocList::iterator i;
DWORD totalSize = 0;
char buf[1024];

if(!allocList) return;

for(i = allocList->begin(); i != allocList->end(); i++) {
sprintf(buf, «% — 50s:\tLINE %d,\tADDRESS %d %d unfreed»,
      (*i)->file, (*i)->line, (*i)->address, (*i)->size);
OutputDebugString(buf);
totalSize += (*i)->size;
}
sprintf(buf, «--------------------------------------------------»);
OutputDebugString(buf);
sprintf(buf, «Total Unfreed: %d bytes», totalSize);
OutputDebugString(buf);
};

Надеюсь, этот проект сделает ваши баг-листы короче, а программы устойчивее. Удачи

 

Интересное

Чтение почты через...
В последнее время довольно популярными стали почтовые системы с web-интерфейсом.Надо заметить, это довольно удобно, особенно для пользователей,которые выходят в интернет с разных машин.Для...
Подробнее...
Сравнение жизни с игрой
Никто не задумывался о том, что жизнь можно считать игрой? По крайней мере, всё идёт по тому же сценарию, что и игры. Когда человек рождается, он получает определённые навыки и умения, которые...
Подробнее...
Тюнинг Windows Server 2003
Как Вы знаете, многие серверные ОС предназначены большей частью для работы сервером, не имея возможностей использования как «домашней» ОС. В этой статье речь пойдет о настройке Windows Server 2003...
Подробнее...
БИЗНЕС В ИНЕТРНЕТЕ
Интернет — один из самых молодых на данный момент рекламоносителей. Преимущественная особенность интернет-рекламы состоит в легком воздействии на определенные узкие целевые аудитории, что просто...
Подробнее...
Unix+ Samba + ftpd,...
Есть такая проблема: сложно найти ftpd, понимающий перекодировку имен файлов. Если хранить файлы на сервере в koi8, то ftpшник выдает винде крякозябры. Если хранить в CP1251, то ftp не передает...
Подробнее...
Какой должен быть сайт
В российском интернете уже существует десятки, а то и сотни тысяч сайтов, но лишь несколько сотен действительно достойны внимания пользователя. Интернет в России реально действует только два-три...
Подробнее...
Увеличение...
Невысокая производительность и плохой доступ к информации часто вызваны неэффективностью каналов глобальной сети. Это ведет к снижению продуктивности, недовольству клиентов и несоблюдению правовых...
Подробнее...
Обзор ОС Windows Server...
Сервер Windows Server 2003 Datacenter Edition разработан специально для удовлетворения потребностей бизнеса в высокой масштабируемости, доступности и надежности и позволяет создавать...
Подробнее...
Служба Доменных Имен
Служба Доменных Имен предназначена для того, чтобы машины, работающие в Internet, могли по доменному имени узнать IP-адрес нужной им машины, а также некоторую другую информацию; а по IP-номеру...
Подробнее...
Сравнение жизни с игрой
Никто не задумывался о том, что жизнь можно считать игрой? По крайней мере, всё идёт по тому же сценарию, что и игры. Когда человек рождается, он получает определённые навыки и умения, которые...
Подробнее...