Подтвердить что ты не робот

Утечка памяти в C, С++; забыл сделать бесплатно, удалить

Мы выделяем память в C, используя malloc и в С++, используя new. Я знаю, что выделенная память должна быть освобожденными или возвращенными ОС, используя свободный в C и удалять на С++. Если я забыл использовать free/delete после выделения памяти, это означает, что произойдет утечка памяти.

Теперь, мой вопрос: это утечка памяти только в течение периода выполнения программы; или это постоянная утечка/потеря или она снова получена после перезапуска системы? Каков внутренний процесс? Что означает утечка/потеря памяти?

Я был бы очень благодарен, если бы кто-нибудь мог объяснить это подробно или предоставить мне несколько хороших ссылок.

ОБНОВЛЕНИЕ 1

После прочтения некоторых ответов я узнал, что память возвращается в ОС/систему после завершения программы, если это так, почему каждый должен так заботиться об утечке памяти, и почему очень важно предотвратить утечку памяти?

ОБНОВЛЕНИЕ 2

Таким образом, следует предотвратить утечку памяти, чтобы система не разбилась из-за нехватки памяти для целей распределения.

ОБНОВЛЕНИЕ 3

Итак, прочитав все ответы, я понял, что утечка памяти - это очень важные проблемы, чтобы предотвратить сбои системы. Но для начинающего, как я, как я могу быть уверенным, что моя программа полностью свободна от утечки памяти. Я пытаюсь сделать бесплатный, удалить, если я использую malloc, но иногда, но он становится беспорядочным. Есть ли какой-либо инструмент или метод, который я могу использовать, чтобы узнать, протекает ли моя программа с утечкой памяти?

ОБНОВЛЕНИЕ 4

После прочтения ответов я теперь понял важность свободного от утечки памяти кода, меньше использования новых/удаления, больше использования STL, узнал новые вещи, такие как RAII, valgrind и хорошие методы программирования. Спасибо всем:)

4b9b3361

Ответ 1

Это за процесс. Когда ваш процесс завершается, выделенная память возвращается ОС для использования другими процессами (новыми или существующими). ​​

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

Можно утверждать, что для небольшого процесса с коротким временем жизни утечки памяти допустимы, поскольку просочившаяся память будет мала по количеству и недолговечна.

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

Ответ 2

Утечка памяти просто означает, что ваше приложение не сможет освободить выделенную память. Как только ваша программа закончится, все зависит от ОС. Каждая современная ОС вернет всю память, используемую приложением, поэтому, как только ваш процесс завершится, он будет очищен.

Но C/С++ не гарантирует, что ОС это сделает. На некоторых платформах возможно потерять память до перезагрузки.

Таким образом, проблема с утечками памяти двоичная:

  • на нескольких платформах, которые система может перезагрузить, чтобы восстановить память. На большинстве платформ это не-isssue, хотя утечка некоторых других типов ресурсов может все еще вызвать проблемы.
  • Пока ваша программа работает, она выделяет память, которую она никогда не освобождает, а это означает, что она будет использовать все больше и больше памяти. Если ваша программа предназначена для работы в течение длительного времени, она может закончиться использованием всей доступной памяти на компьютере и впоследствии сбой.

Многие краткосрочные программы фактически игнорируют утечки памяти, потому что они знают, что скоро ее очистят ОС. Насколько я знаю, компилятор Microsoft С++ делает это. Они знают, что после вызова компилятора он работает максимум на пару минут. (и они знают, что он работает в Windows, где ОС восстанавливает память, как только процесс завершается). Так что это нормально, что он теряет некоторую память здесь и там.

Что касается того, как избежать утечек памяти, не создавайте их.

Вы рискуете утечки памяти каждый раз, когда используете новый/удалить, поэтому не делайте этого.

Когда вам нужен массив данных, сделайте следующее:

std::vector<char> vec(200);

вместо этого:

char* arr = new char[200];

Первый так же эффективен, но вам не нужно явно вызывать delete, чтобы освободить его std::vector использует RAII для управления внутренними ресурсами. И вы должны сделать то же самое - либо с помощью готовых RAII-классов, таких как vector, shared_ptr, или почти любого другого класса в стандартной библиотеке или в Boost или путем написания собственного.

Как правило, ваш код не должен содержать никаких новых/удаленных вызовов, за исключением конструктора/деструктора для класса, ответственного за управление этим распределением.

Если объект выделяет требуемую память в конструкторе и освобождает его в деструкторе (и правильно обрабатывает копирование/присвоение), вы можете просто создать локальный экземпляр класса в стеке, когда вам это нужно, и он не будет, не может, утечка памяти.

Ключом к утечке памяти в С++ является не вызов new/delete.

Ответ 3

Операционная система будет отслеживать память, и как только ваша программа завершится, будет восстановлена ​​вся память. Это просто означает, что ваше приложение потеряло часть выделенной памяти.

Обратите внимание, что это может не распространяться на некоторые операционные системы, но будет иметь место в любой системе типов windows/unix/mac

Ответ 4

Re: инструменты для обнаружения утечки памяти

Если вы используете ОС на базе Linux для разработки, вы можете попробовать использовать valgrind (http://valgrind.org/) для обнаружения утечки памяти.

valgrind --leak-check=full ./compiled_binary

Если программа была скомпилирована с помощью отладочных символов (например, для gcc, включите флаг -g), valgrind также сообщит вам точную строку кода, в которой была выделена утечка памяти. Это значительно облегчит задачу отслеживания и устранения утечек.

Плюсы: это бесплатно

Минусы: AFAIK, он работает только в Linux

Обновление

Как видно на http://valgrind.org/info/platforms.html, valgrind переносится на другие ОС (и платформы), включая MacOSX, FreeBSD и NetBSD.

Обновление 2

(немного от темы, но...)

Хорошая вещь об использовании valgrind заключается в том, что она намного больше, чем просто проверка на утечку памяти. См. http://valgrind.org/info/tools.html

Я сконфигурировал buildbot для запуска valgrind (и splint) во всех моих ночных сборках, и это оказалось бесценным!

Ответ 5

Существуют инструменты для обнаружения утечек памяти, например. Purify.

Ответ 6

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

Существует идея программирования, называемая инициализацией ресурсов (RAII). Это говорит о том, что "если вам нужно выделить память, которую нужно удалить, или убедитесь, что открываемое вами содержимое закрывается, оберните его в объект, который вы создаете в стеке. Таким образом, когда объект выходит из области действия, деструктор автоматически вызывается, и вы удаляете свой ресурс в деструкторе."

Общие утечки памяти происходят, когда вы пишете "новый" в коде, но ваша функция завершается перед вызовом delete. Иногда вы сталкиваетесь с утверждением "return" слишком рано, в другое время исключение бросается и ломается после вашего заявления "удалить". После RAII вы можете убедиться, что эти несчастные случаи не происходят.

Ответ 7

Это утечка памяти.

В основном это означает, что эта память не будет восстановлена ​​до тех пор, пока процесс не будет уничтожен.

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

Это только серьезная проблема, если это происходит неоднократно. Если это произойдет, программа будет продолжать использовать все больше и больше памяти, чем дольше она будет работать, прежде чем в конечном итоге произойдет сбой. Пользователям необходимо будет регулярно перезапускать приложение, чтобы избежать этого, или использовать слишком много системных ресурсов.

Ответ 8

Обновление 1:
Если у вас есть простое приложение, которое работает один раз, делает его дело и завершается, то утечка памяти не так важна. Его по-прежнему очень плохая практика, и если вы придерживаетесь стиля кодирования, вы полностью исключаете утечки в своем коде, тогда вы, вероятно, поместите те же самые утечки в приложения, где это важно - те, которые работают в течение нескольких дней, недель или лет. У нас есть приложение, которое утечки, поэтому мы перезапускаем его каждый месяц. Это не идеальная ситуация.

Обновление 2:
да, в значительной степени. Но утечки памяти следует предотвращать просто потому, что они являются ошибкой, и вы никогда не должны писать код с представлением о том, что ошибки приемлемы.

Обновление 3:
Лучший способ предотвратить утечку памяти - не использовать malloc/free в первую очередь. Если вы используете С++ для чтения в RAII, используйте классы и скопируйте объекты, это гарантирует, что у вас никогда не будет утечек... почти все время. Если вам нужно явно выделить память, убедитесь, что вы ее отслеживаете. Если это означает, что вам нужен глобальный объект где-нибудь, где хранятся указатели, тогда сделайте это. Если это означает, что у вас есть класс коллекции, в котором хранятся указатели, то получите его. Никогда не распределяйте память на локальную переменную, о которой вы могли бы забыть, может вернуться из функции, не перейдя через свободный вызов, может перейти к другой функции, которая освободится, которая не будет вызвана. Для этого требуется чувство дисциплины (требуется не большая дисциплина), но многие люди скажут вам, что такая же добродетель необходима для написания хорошего, правильного, хорошо продуманного, без ошибок кода в любом случае (и они были бы правы - если вы когда-либо видели взломанный код по сравнению с хорошо продуманным кодом, вы сразу сможете увидеть разницу).

Примечания:
даже используя собранный мусором язык, вы все равно получите утечку памяти. Люди добавляют объекты в коллекции, а затем забывают их удалить, и поэтому объект остается в памяти навсегда. Это считается утечкой. Его разумно распространенный в языках GC, чтобы сделать это, поскольку люди думают, что GC сделает всю работу за них. Опять же, требуется кодирование/дизайн - знать, что вы делаете, предотвратит эти ошибки.

Утечки памяти могут возникать даже без использования malloc/new. Помните о переписывании переменных указателя, которые уже указывают на некоторую память. Мой самый большой источник утечек был с MSXML, я бы создал CComPtr объекта XML, а затем вызвал метод для получения элемента, передав объект в метод в качестве параметра. К сожалению, класс был добавлен во внутренний указатель, и метод просто перезаписал бы его новым указателем, оставив старые данные утечкой. Мораль здесь заключается в том, что, если вы используете класс интеллектуального указателя, убедитесь, что знаете, что он делает, особенно с его оператором литья.

Инструменты:
вам не нужно покупать Purify при работе в Windows. Microsoft предлагает UMDH, который принимает моментальные снимки вашей памяти. Возьмите 2 моментальных снимка и сравните их с помощью инструмента, и вы можете увидеть распределения, которые со временем увеличиваются, не будучи выделенными. Его не очень, но он работает.

Ответ 9

Несколько точек для добавления:

  • Научитесь правильно работать в форме в начале - свободной памяти, очень сложно исправить плохую привычку.
  • Память не является единственным ресурсом, который должен управляться или управляться с помощью new/delete.

    Например, некоторый объект может содержать временный файл, который должен быть удален в конце. Обычно такие вещи привязываются к некоторому объекту, поэтому, если вы забываете удалить объект, вы забываете отсоединить файл и... Этот ресурс не возвращается даже при перезапуске системы.

    Там много других подобных ресурсов, которые привязаны к объектам и управляются с помощью новых /delete: файлов, сокетов, разделяемой памяти, подключений к базе данных и т.д. Таким образом, все методы, которые вы изучите для управления памятью, помогут вам управлять этими другими, ограниченными ресурсами, которые вам придется использовать.

Ответ 10

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

Эта память берется из так называемой "кучи". Что является локальным для вашей программы и полностью удаляется, когда заканчивается ваша программа. Таким образом, "единственный" вред, который может сделать ваша программа для других программ, работающих в системе, и ОС - это то, что они также могут не выделять память, потому что ваша программа "съела" все. Как только вы завершаете свою программу, другие должны нормально работать, если они не разбились между тем из-за проблем с распределением.

Ответ 11

Инструмент для мониторинга утечек памяти должен переопределять новые и удалять операторы. Это позволяет вам поддерживать список памяти, который был выделен и не освобожден. Таким образом, если конкретный объект должен освободить всю память, которую он использует, этот механизм дает вам возможность убедиться, что он действительно освободил память.

Ответ 12

Наряду с Purify вы можете попробовать бесплатную альтернативу: valgrind. Оговорка заключается в том, что valgrind - это специфическое для Linux решение.

Ответ 13

Чтобы ответить на обновление 3, обычно есть способ указать, имеет ли ваш процесс какие-либо выдающиеся распределения памяти. _heapwalk (под Win32) позволит вам пройти все ваши распределения, и вы увидите, есть ли какие-либо выдающиеся возможности.

Помимо этого, вероятно, стоит обернуть ваши вызовы malloc/new, чтобы вы записывали файл и номер строки каждого распределения, когда это происходит. Затем в вашем переопределенном delete/free вы удалите его из списка.

e.g(будьте предупреждены, что это полностью непроверенный код, поэтому он, вероятно, не будет работать с летучей мыши)

struct MemoryAllocEntry
{
    char* pFile;
    char* pLine;
};

extern std::map< MemoryAllocEntry > g_AllocList;

inline void* MyMemAlloc( size_t size, char* pFile, char* pLine )
{
    MemoryAllocEntry mae;
    void* pRet = malloc( size );
    mae.pFile = pFile;
    mae.pLine = pLine;

    g_AllocList[pRet] = mae;

    return pRet;
}

inline void MyMemFree( void* pPtr )
{
    std::map< MemoryAllocEntry >::iterator iter = g_AllocList.find( pPtr );
    if ( iter != g_AllocList.end() )
    {
         g_AllocList.erase( iter );
    }
    free( pPtr );
}

#ifdef _DEBUG
    #define malloc( x ) MyMemAlloc( (x), __FILE__, __LINE__ )
    #define free( x ) MyMemFree( (x) )
#endif

Затем вам нужно пройти через g_AllocList, чтобы найти любые выдающиеся распределения. Вышеупомянутое, очевидно, работает только для malloc и бесплатно, но вы можете заставить его работать и для нового, и для удаления (MFC делает это, например).

Ответ 14

В ответ на ваш вопрос и обновите 1,:

Не все операционные системы поддерживают понятие отдельных процессов, поэтому никогда не будут автоматически очищать вещи.

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

Кроме того, такая платформа, вероятно, используется в системе, которая редко перезагружается и не поддерживает обмен, поэтому любые утечки памяти намного серьезнее, чем они были (например) на рабочем столе.

Правильный способ избежать утечек памяти - это делать меньше явного управления памятью и полагаться на контейнеры, которые управляют файлами для вас, например STL в С++ (соответствующие части).

Низкоуровневые встроенные программисты, использующие C, часто избегают утечек памяти, статически выделяя все при запуске. Программисты C также могут использовать распределение стека с alloca(), чтобы избежать возможных утечек памяти (но они должны точно понимать, как это работает).

Ответ 15

Это память, назначенная процессу. Вы вернете его, когда вы убьете процесс.

Ответ 16

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

Ответ 17

Отвечая на изменение -

Если ваша программа предназначена для запуска. так что-то, а потом прекратите, тогда вам не нужно слишком беспокоиться о освобождении памяти. Это важно для программ, которые работают некоторое время. Если ваш веб-браузер не освободил память, он использовал для отображения страницы, и вскоре он будет использовать всю память на вашем компьютере.

Это хорошая практика, чтобы освободить память в любом случае, хотя небольшие программы, которые запускаются однажды, имеют привычку превращаться в другие вещи, и это хорошая привычка вступать.

Ответ 18

Когда программа заканчивается в Windows, она освобождает не только память, но все ручки открываются (исправьте меня, если я ошибаюсь)