Как определить утечку памяти в программе на С++?
>Как определить утечку памяти в программе на С++?Хороший вопрос ;-) - это один из самых проблеммных вопросов C/C++ (разработчики Java мотивирует этим отказ от прямого управления памятью в синтаксисе языка)... Но тут - 2 вопроса:
1. как определить сам факт утечки памяти?
2. как определить место утечки памяти?1. в долгосрочно работающей программе это видно по наблюдаемому уменьшению free памяти в системе - но это "не факт" при недостаточно большом времени: могут наблюдаться циклические изменения, связанные просто с работой подсистемы управления памятью в зависимости от OS...
2. никак. Анализировать код программы.
Это и явилось одной из причин создания Java.
>Это и явилось одной из причин создания Java.
Это явилось причиной широкой распространенности технологии "сборки мусора", наличие которой можно наблюдать почти во всех языках высокого уровня(я не уверен в слове "почти":-).
>>Это и явилось одной из причин создания Java.
>Это явилось причиной широкой распространенности технологии "сборки мусора", наличие которой можно наблюдать
>почти во всех языках высокого уровня(я не уверен в слове "почти":-).
>Со словом "почти" - всё в порядке...
Всё определяется синтаксическими конструкциями языка:
- невозможно и представить работу LISP без сборки мусора...
- но ... "чисто компилирующие" семантики C/C++ или тот-же давний FORTRAN - так же трудно представить со сборщиком мусора - как корова с седлом...И потом - всё хорошо в меру: представьте себе приложение в realtime OS (QNX, VxWorks ...) ... со сборщиком мусора: "такое ночью приснится - не проснёшься" (с).
>Как определить утечку памяти в программе на С++?Я встречал такой метод:
1. Создаётся глобальная и доступная для всей программы переменная int gMemCounter = 0;
2. Для всех функций, которые выделяют или освобождают память (malloc, free, new, delete, mysql_store_result, mysql_free_result и т.д.) создаются соответсвтующие макросы, которые увеличивают или уменьшают соответственно наш глобальный счётчик на единицу (если прога многопоточная, то надо ещё и мьютекс поюзать), например:
#ifdef DEBUG
#define MALLOC(ptr,size) \
ptr = malloc (size);
pthread_mutex_lock(&gMemMutex); \
gMemCounter++; \
pthread_mutex_unlock(&gMemMutex);
#else
#define MALLOC(ptr,size) ptr = malloc (size);
#endif3. В самом конце выполнения программы проверяется наш счётчик - он, очевидно, должен быть равен нулю, если это не так, то либо есть утечка, либо мы недостаточно аккуратны.
Этот способ позволяет только определить наличие утечки, но не говорит - где она, у него масса недостатков, но всё же это единственное решение, которое я встречал, и я считаю его вполне применимым.
>#ifdef DEBUG
>#define MALLOC(ptr,size) \
>ptr = malloc (size);
>pthread_mutex_lock(&gMemMutex); \
>gMemCounter++; \
>pthread_mutex_unlock(&gMemMutex);
>#else
>#define MALLOC(ptr,size) ptr = malloc (size);
>#endifЭтот макрос в 70% случаев не будет работать корректно. Так, например, для констукции вида
if (condtion)
MALLOC(ptr, size);после препроцессирования мы получим (выровненно для наглядности):
if (condition)
ptr = malloc (size);
pthread_mutex_lock(&gMemMutex);
gMemCounter++;
pthread_mutex_unlock(&gMemMutex); ;если условие выполняет - ошибка останется "незамеченной", если же не выполняется - мы увеличим счетчик без выделения памяти - итог десятки человеко-часов на поиски ошибки выделения памяти.
Думаю правильным было бы использование следующей конструкции:
#ifdef DEBUG
#define MALLOC(ptr,size) do { \
ptr = malloc (size); \
pthread_mutex_lock(&gMemMutex); \
gMemCounter++; \
pthread_mutex_unlock(&gMemMutex); \
while (0)
#else
#define MALLOC(ptr,size) ptr = malloc (size)
#endif
>#ifdef DEBUG
>#define MALLOC(ptr,size) \
>ptr = malloc (size);
>pthread_mutex_lock(&gMemMutex); \
>gMemCounter++; \
>pthread_mutex_unlock(&gMemMutex);
>#else
>#define MALLOC(ptr,size) ptr = malloc (size);
>#endifЭтот макрос в 70% случаев не будет работать корректно. Так, например, для констукции вида
if (condtion)
MALLOC(ptr, size);после препроцессирования мы получим (выровненно для наглядности):
if (condition)
ptr = malloc (size);
pthread_mutex_lock(&gMemMutex);
gMemCounter++;
pthread_mutex_unlock(&gMemMutex); ;если условие выполняет - ошибка останется "незамеченной", если же не выполняется - мы увеличим счетчик без выделения памяти - итог десятки человеко-часов на поиски ошибки выделения памяти.
Думаю правильным было бы использование следующей конструкции:
#ifdef DEBUG
#define MALLOC(ptr,size) do { \
ptr = malloc (size); \
pthread_mutex_lock(&gMemMutex); \
gMemCounter++; \
pthread_mutex_unlock(&gMemMutex); \
while (0)
#else
#define MALLOC(ptr,size) ptr = malloc (size)
#endif
>
>Думаю правильным было бы использование следующей конструкции:
>#ifdef DEBUG
>#define MALLOC(ptr,size) do { \
>ptr = malloc (size); \
>pthread_mutex_lock(&gMemMutex); \
>gMemCounter++; \
>pthread_mutex_unlock(&gMemMutex); \
>while (0)
>#else
>#define MALLOC(ptr,size) ptr = malloc (size)
>#endif:)
Респект абсолютный и полный, но недочёт есть и тут :) - do while - абсолютно лишне. Окончательный вариант:
#ifdef DEBUG
#define MALLOC(ptr,size) { \
ptr = malloc (size); \
pthread_mutex_lock(&gMemMutex); \
gMemCounter++; \
pthread_mutex_unlock(&gMemMutex); \
}
#else
#define MALLOC(ptr,size) ptr = malloc (size)
#endifПрошу отметить, что суть вопроса не в правильности составления макроса, а в принципе определения утечки :)
>Респект абсолютный и полный, но недочёт есть и тут :) - do
>while - абсолютно лишне.Оно необходимо. В твоей версии при
if(...)
MALLOC(p, s);
else
....;получится фигня.
>#else
>#define MALLOC(ptr,size) ptr = malloc (size)#define MALLOC(ptr,size) (ptr = malloc(size))
>#endif
P.S. А по теме - FAQ из ru.unix.prog.
>Оно необходимо. В твоей версии при
>
>if(...)
> MALLOC(p, s);
>else
> ....;
>
>получится фигня.Согласен, был не прав :) Но для меня это не критично -я считаю хорошим стилем ставить везде скобки явно.
Спасибо за наводку, нашёл много полезных вещей. Вот ссылки:
http://bsd.opennet.ru/base/faq/prog_faq.txt.html
http://mifi3.pp.ru/howto/C++Programming-HOWTO-11.htmlВо FreeBSD-портах накопал следующее:
devel/boehm-gc http://www.hpl.hp.com/personal/Hans_Boehm/gc/
devel/dmalloc http://dmalloc.com/docs/5.2.0/online/dmalloc.html
devel/mprof
devel/uds http://frost.flewid.de/uds/
Сам пока не юзал, но судя по описанию - очень даже ничего.
можно сделать два счетчика,
gMemCounter = 0;
gMemPlace = 0;и если у тебя gMemCounter будет инкрементироваться на единицу при каждом выделении памяти, то gMemPlace на 2 в степени gMemCounter. в случае утечки получишь точное место
>>Как определить утечку памяти в программе на С++?
>
>Я встречал такой метод:
>1. Создаётся глобальная и доступная для всей программы переменная int gMemCounter =
>0;
>2. Для всех функций, которые выделяют или освобождают память (malloc, free, new,
>delete, mysql_store_result, mysql_free_result и т.д.) создаются соответсвтующие макросы, которые увеличивают или
>уменьшают соответственно наш глобальный счётчик на единицу (если прога многопоточная, то
>надо ещё и мьютекс поюзать), например:
>#ifdef DEBUG
>#define MALLOC(ptr,size) \
>ptr = malloc (size);
>pthread_mutex_lock(&gMemMutex); \
>gMemCounter++; \
>pthread_mutex_unlock(&gMemMutex);
>#else
>#define MALLOC(ptr,size) ptr = malloc (size);
>#endif
>
>3. В самом конце выполнения программы проверяется наш счётчик - он, очевидно,
>должен быть равен нулю, если это не так, то либо есть
>утечка, либо мы недостаточно аккуратны.
>
>Этот способ позволяет только определить наличие утечки, но не говорит - где
>она, у него масса недостатков, но всё же это единственное решение,
>которое я встречал, и я считаю его вполне применимым.
Ищи на
http://citforum.ru
там где-то что-то было, но, насколько я помню (давно смотрел), как-то своеобразно...
а у нас взяли недавно на работу "интернет-оператора"
ходит девочка по чатам и где попало такие вот с-с-сылочки расставляет для рекламы с-с-с-айта
А, Арлекин, признайся честно!
мучают меня подозрения :-))))
:) Подозрения мучают мусарню. Из тебя, детка, девочка еще может и получится, а я староват уже.
>Как определить утечку памяти в программе на С++?Рекомендую valgrind: http://developer.kde.org/~sewardj/