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

Я просто дам свое мнение, почему я использую исключительный имена.

, Например, я должен получить все поля от пользователя:

-- Select every fields from 'user' table
SELECT * FROM user

мне нужно имя пользователя, которому 21 год:

-- Select every fields from 'user' table which have 21 years old
SELECT * FROM user WHERE age = '21'

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

35
задан seg.server.fault 5 August 2009 в 12:52
поделиться

18 ответов

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

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

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

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

33
ответ дан 27 November 2019 в 06:48
поделиться

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

0
ответ дан 27 November 2019 в 06:48
поделиться

Ответ на редактирование -

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

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

0
ответ дан 27 November 2019 в 06:48
поделиться

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

0
ответ дан 27 November 2019 в 06:48
поделиться

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

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

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

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

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

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

1
ответ дан 27 November 2019 в 06:48
поделиться

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

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

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

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 и free, но вы также можете заставить его работать для new и delete (например, MFC делает это).

1
ответ дан 27 November 2019 в 06:48
поделиться

Вдоль с Purify вы можете попробовать бесплатную альтернативу: valgrind. Там оговорено, что valgrind - это решение для Linux.

1
ответ дан 27 November 2019 в 06:48
поделиться

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

1
ответ дан 27 November 2019 в 06:48
поделиться

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

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

1
ответ дан 27 November 2019 в 06:48
поделиться

Несколько моментов, которые следует добавить:

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

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

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

2
ответ дан 27 November 2019 в 06:48
поделиться

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

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

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

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

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

2
ответ дан 27 November 2019 в 06:48
поделиться

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

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

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

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

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

3
ответ дан 27 November 2019 в 06:48
поделиться

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

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

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

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

2
ответ дан 27 November 2019 в 06:48
поделиться

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

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

valgrind --leak-check=full ./compiled_binary

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

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

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

Обновление

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

Обновление 2

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

Преимущество valgrind в том, что он делает гораздо больше, чем просто проверяет утечки памяти.

5
ответ дан 27 November 2019 в 06:48
поделиться

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

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

9
ответ дан 27 November 2019 в 06:48
поделиться

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

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

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

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

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

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

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

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

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

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

char* arr = new char[200];

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

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

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

16
ответ дан 27 November 2019 в 06:48
поделиться

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

4
ответ дан 27 November 2019 в 06:48
поделиться

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

0
ответ дан 27 November 2019 в 06:48
поделиться