Каталог статей

Главная » Статьи » C/С++

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

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

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

Для обнаружения подобных ошибок создано специализированное программное обеспечение (типа 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;
  DWORD size;
  char file[64];
  DWORD line;
} 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);
 };

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

Категория: C/С++ | Добавил: virusik (03.07.2009)
Просмотров: 1031 | Комментарии: 1 | Рейтинг: 0.0/0 |
Всего комментариев: 0
Имя *:
Email *:
Код *:
вход на сайт
Категории раздела
C/С++ [24]
статьи о языке C/С++
Visual FoxPro [1]
информация о языке Visual FoxPro
.NET [24]
статьи о языке программирования .NET
ваши статьи [4]
здесь вы можете размещать сваи статьи
модинг [4]
статьи о модинге ПК
Поиск по сайту
наши опросы
каким браузерам вы пользуетесь
Всего ответов: 21
Мини-чат
помощь проекту
помоги проекту
ЯндексЯндекс. ДеньгиХочу такую же кнопку
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Каталог http://www.internetmir.ru Лучшие сайты интернета в каталоге Intenetmir
  • Delphi.int.ru - Сообщество программистов: общение, помощь, обмен опытом.
    реклама 88х31
    Каталог сайтов. Раскрутка. Хостинг. Каталог ссылок. Информационный портал - Старого.NET Шпоры, курсовые, пособия, рефераты, ВУЗы.
    Статистика
    webgari.com Рейтинг сайтов
    Раскрутка сайтов
    Яндекс цитирования
    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0