Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Меры избежания утечек памяти


Автор: andrew_121 25.5.2009, 00:31
Сабж.

Доброго времени суток!

Банальный вопрос. Но все же...
Как избежать утечек памяти в большом проекте? Что для этого стОит делать, а чего не стОит?
Может все объекты "собственного" производства унаследовать от базового, который в себе переопределит operator new, operator delete, и в нем вести учет выделенной/освобожденной памяти. От утечек это конечно не избавит, но хотя бы можно будет обнаружить это на ранней стадии разработки.

В общем вопрос понятен.

Автор: REZiaMIX 25.5.2009, 01:16
Как то делал проект, средний по объему.
Никак не мог уловить утечку памяти(видно было по диспетчеру задач).
За 10 секунд в проект была вставлена брутальность в виде:
Код


class mm
{
private:
    size_t alloc;
    size_t freed;
public:
    mm()
    {
        alloc = freed = 0;
    }
    mm~()
    {
        //Пишем отчет в файл
    }
    void* getmem(size_t size)
    {
        alloc+=size;
        return malloc(size);
    }
    void freemem(void * ptr)
    {
        freed += sizeof(ptr);
        free(ptr);
    }
}mm_inst;
#undef malloc
#define malloc mm_inst.getmem
#define free mm_inst.freemem

еще 3 минуты , и утечка была найдена  smile 
В Borland C++ Builder есть хорошая штука - CodeGuard.
Сообщает не только об утечках , но и о других ошибках.
Уверен на все %сто% , что и для других более-менее популярных сред есть аналогичные инструменты!
Еще вспомнилось , в вижуал студии есть встроенная поддержка для контроля утечек памяти.
Надо прописать какие то дефайны. 

Автор: andrew_121 25.5.2009, 01:24
REZiaMIX, C getmem() - Согласен. А с freemem() - Нет!
ГетМем() правильно щитает выделенную память, а ФриМем - нет! Он щитает только размер указателя. Какая польза ??? Даже если указатель разименовать, он будет щитать размер объекта на который указывает. Что-то тут не то...
Да и ваще, мне что в проекте переименовать все operator new, operator delete, и заменить их на методы? Как-то не логично.

Автор: REZiaMIX 25.5.2009, 01:27
Хм , и в правду , надо порыться в исходниках.
Вот http://www.rsdn.ru/article/vcpp/leaks.xmlчуток для visual c++;

Добавлено @ 01:39
Код


class mm
{
private:
    size_t alloc;
    size_t freed;

public:
    mm()
    {
        alloc = freed = 0;
    }
    void* getmem(size_t size)
    {
        alloc+=size;
        char * ptr = (char*)malloc(size+sizeof(size_t));
        memcpy(ptr,&size,sizeof(size_t));
        ptr+=sizeof(size_t);
        return (void*)ptr;
    }
    void freemem(void * ptr)
    {
        char * ptrc = (char*)ptr;
        size_t len;
        memcpy(&len,ptrc-4,sizeof(size_t));
        freed+= len;
        free(ptrc-4);
    }
}mm_inst;
#undef malloc
#define malloc mm_inst.getmem
#define free mm_inst.freemem


Для смысла будет понятно)

Добавлено @ 01:40
переименовывать в моем случае ничего не надо , #define все сделает сам smile

Автор: andrew_121 25.5.2009, 02:27
REZiaMIX, ну допустим, я воспользуюсь твоим примером. память он выделяет и освобождает. а как быть с конструкторами/деструкторами?
их что, явно вызывать? smile 
в общем не то...

Автор: Rickert 25.5.2009, 03:58
Воспользоваться или реализовать самому умные указатели.

Автор: andrew_121 25.5.2009, 08:50
Цитата(Rickert @  25.5.2009,  03:58 Найти цитируемый пост)
Воспользоваться или реализовать самому умные указатели.

Да. Спасибо.

Автор: azesmcar 25.5.2009, 08:56
Цитата(Rickert @  25.5.2009,  03:58 Найти цитируемый пост)
Воспользоваться или реализовать самому умные указатели. 

и это тоже..но в основном ответ на вопрос звучит так - писать правильный кодsmile (как ни странно)
Пример где использование умных указателей не спасет от возможной утечки памяти
Код

myfunction
(
    std::auto_ptr<A>(new A()), std::auto_ptr<A>(new A())
);


Автор: Alek86 25.5.2009, 09:09
azesmcar, почему не спасет? запятая ж является точкой следования

andrew_121, переопределять глобальные operator new, operator delete, operator new[], operator delete[]
если в приложении критична скорость, переопределять их с помощью #ifdef

ну и есть куча тулзей, что тебе лики предоставит

Автор: azesmcar 25.5.2009, 09:11
Цитата(Alek86 @  25.5.2009,  09:09 Найти цитируемый пост)
почему не спасет? 

при возникновении исключения в одном из конструкторов - может случится утечка. Например если очередь подстановки параметров функции (которая кстати неопределена по стандарту - а это значит что компилятор волен делать это как его компиляторской душе угодно) будет происходить так

Цитата

1.new A() //конструктор класса А для первого обьекта
2.new A() //конструктор класса А для второго обьекта
3.std::auto_ptr<A> конструктор класса auto_ptr для первого обьекта
4.std::auto_ptr<A> конструктор класса auto_ptr для второго обьекта

если на втором шаге произойдет исключение - будет утечка.

Автор: Alek86 25.5.2009, 09:13
Цитата(Rickert @  25.5.2009,  03:58 Найти цитируемый пост)
Воспользоваться или реализовать самому умные указатели.

умные указатели - не панацея

если возможны циклические ссылки, то shared_ptr не поможет
придется добавлять weak_ptr и серьезно проектировать, ибо вики хорошо так добавляют в сложности проги

Добавлено через 2 минуты и 29 секунд
тьфу, это ж обьява функции
кто ж так пишет обьявы, что не заметишь....

Автор: azesmcar 25.5.2009, 09:18
Цитата(Alek86 @  25.5.2009,  09:13 Найти цитируемый пост)

Добавлено через 2 минуты и 29 секунд
тьфу, это ж обьява функции
кто ж так пишет обьявы, что не заметишь.... 

да нет, это вызов функции smile

Добавлено через 48 секунд
Код

foo(std::auto_ptr<A>(new A()), std::auto_ptr<A>(new A()));

так лучше?

Автор: Alek86 25.5.2009, 09:23
ага, имхо, намного
совсем не так прочел - слишком стиль от привычного мне отличается smile

Автор: azesmcar 25.5.2009, 09:24
Цитата(Alek86 @  25.5.2009,  09:23 Найти цитируемый пост)
ага, имхо, намного
совсем не так прочел - слишком стиль от привычного мне отличается smile


строка длинная была smile 

Автор: sparn 25.5.2009, 11:30
есть несколько простых правил, придерживаясь которых можно избежать большинства возможных утечек, например: избегать по максимуму ручного выделения и удаления памяти (например использовать контейнеры которые подчистят сами при удалении), удалять память там где выделяешь, написал new напиши сразу delete... Исходя из собственного опыта про умные указатели могу сказать что они не исключают утечек и если уж таковые произошли то процесс выявления и избавиления от них может стать настоящим кошмаром >_<.

для проверки и выявления тяжелых случаев утечек я использовал http://www.softwareverify.com/cpp/memory/index.html.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)