Утечки памяти когда-либо в порядке?

214

Насколько приемлемо иметь утечку памяти в вашем приложении C или С++?

Что делать, если вы выделяете некоторую память и используете ее до самой последней строки кода в своем приложении (например, деструктор глобального объекта)? До тех пор, пока потребление памяти не будет расти со временем, можно ли доверять ОС, чтобы освободить вашу память для вас, когда ваше приложение завершается (в Windows, Mac и Linux)? Вы даже считали бы это реальной утечкой памяти, если бы память использовалась непрерывно, пока она не была освобождена ОС.

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

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

  • 48
    Если потребление памяти не растет со временем, это не утечка.
  • 4
    Большинство приложений (включая все программы .NET) имеют как минимум несколько буферов, которые выделяются один раз и никогда не освобождаются явно. Поэтому определение mpez0 более полезно.
Показать ещё 3 комментария
Теги:
memory-leaks

49 ответов

288
Лучший ответ

Нет.

Как профессионалы, вопрос, который мы не должны задавать себе, заключается в следующем: "Всегда ли так хорошо?" а скорее "Есть ли веские основания для этого?" И "охота на эту утечку памяти - это боль" - не очень хорошая причина.

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

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

Это похоже на предупреждения компилятора - будет ли предупреждение опасным для моего конкретного приложения? Возможно, нет.

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

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

Хотя возможно, что может возникнуть обстоятельство, когда стоимость/риск удаления этого оборудования превышает стоимость/риск его оставления, и могут быть ситуации, когда это было безвредно, если бы я увидел этот вопрос, размещенный на SurgeonOverflow.com и увидел любой ответ, отличный от "нет", это серьезно подорвало бы мою уверенность в медицинской профессии.

-

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

  • 50
    Правда и не правда одновременно. В конечном итоге большинство из нас - наемные рабы, и любое стремление к мастерству должно отойти на второй план от требований бизнеса. Если эта сторонняя библиотека имеет утечку и экономит 2 недели работы, может быть экономическое обоснование для ее использования и т. Д.
  • 3
    В любом случае, я бы использовал библиотеку, если бы это было чем-то, что мне было нужно, и не было достойных альтернатив, но я бы сообщал об ошибке с сопровождающими.
Показать ещё 20 комментариев
80

Я не считаю, что это утечка памяти, если количество используемой памяти не растет. Наличие некоторой неизданной памяти, хотя и не идеальной, не является большой проблемой, если объем требуемой памяти не растет.

  • 0
    Технически, это все еще утечка, потому что остальная часть системы не может использовать эту память.
  • 11
    Технически, утечка - это выделенная память, и все ссылки на нее потеряны. Не освобождать память в конце просто лень.
Показать ещё 12 комментариев
76

Пусть наши определения правильны, во-первых. Утечка памяти - это когда динамически распределена память, например, с помощью malloc(), и все ссылки на память теряются без соответствующего освобождения. Легкий способ сделать это:

#define BLK ((size_t)1024)
while(1){
    void * vp = malloc(BLK);
}

Обратите внимание, что каждый раз вокруг цикла while (1) выделяются байты 1024 (+ служебные), а новый адрес назначается vp; там не осталось указателя на предыдущие блоки malloc'ed. Эта программа, как гарантируется, будет работать до тех пор, пока не закончится куча, и нет возможности восстановить какую-либо память malloc'ed. Память "протекает" из кучи, и ее больше не видно.

То, что вы описываете, звучит как

int main(){
    void * vp = malloc(LOTS);
    // Go do something useful
    return 0;
}

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

Как правило, вы должны избегать утечек памяти. Во-первых, потому что, как высота над вами и топливо в ангаре, память, которая просочилась и не может быть восстановлена, бесполезна; во-вторых, гораздо проще правильно кодировать, а не утечка памяти, с самого начала, чем искать утечку памяти позже.

  • 0
    Теперь рассмотрим несколько десятков из этих распределений. Теперь рассмотрим необходимость переместить «основное» тело в процедуру, которая вызывается несколько раз. Наслаждаться. - Я согласен с мнением, что в этом сценарии такая большая проблема, но сценарии меняются. Как говорится, всегда пишите код, как будто парень, который его поддерживает, знает, где вы живете.
  • 2
    Дело в том, что память, которая распределена по malloc'у и удерживается до тех пор, пока программа не вызовет _exit (), не будет "утечка".
Показать ещё 10 комментариев
38

В теории нет, на практике это зависит.

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

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

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

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

  • 0
    Я не знаю, читали ли вы весь мой вопрос или нет. Я говорю, что память используется до самого конца приложения. Это не растет со временем. Единственное нет нет, это то, что нет вызова для освобождения / удаления.
  • 2
    Тогда это на самом деле не утечка памяти. Утечка памяти - это небольшие объемы неиспользуемой, но не освобожденной памяти, которая с течением времени увеличивается. То, о чем вы говорите, это капля памяти. Не беспокойтесь, если ваша капля не очень большая.
Показать ещё 10 комментариев
33

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

Это неверно. Операционные системы обычно управляют памятью на страницах 4KiB. malloc и другие виды управления памятью получают страницы из ОС и подчиняют их по своему усмотрению. Весьма вероятно, что free() не вернет страницы в операционную систему, в предположении, что ваша программа будет malloc больше памяти позже.

Я не говорю, что free() никогда не возвращает память операционной системе. Это может произойти, особенно если вы освобождаете большие участки памяти. Но нет никакой гарантии.

Важный факт: Если вы не освобождаете память, которая вам больше не нужна, в дальнейшем mallocs гарантированно потребляют еще больше памяти. Но если вы сначала освободите, malloc может вместо этого использовать свободную память.

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

Также см. этот комментарий для получения более подробной информации о том, почему освобождение памяти непосредственно перед завершением плохое.

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

Итак, чтобы убедить людей, я продемонстрирую пример, когда free() делает очень мало пользы. Чтобы сделать математику легко следовать, я буду притворяться, что ОС управляет памятью на 4000 байтовых страницах.

Предположим, вы выделили десять тысяч 100-байтных блоков (для простоты я проигнорирую дополнительную память, которая потребуется для управления этими распределениями). Это потребляет 1 МБ, или 250 страниц. Если вы случайно освободите 9000 из этих блоков, вы останетесь всего на 1000 блоков, но они будут разбросаны по всему месту. По статистике, около 5 страниц будут пустыми. Остальные 245 будут иметь по меньшей мере один выделенный блок в них. Это составляет 980 Кбайт памяти, которые не могут быть восстановлены операционной системой - даже если у вас теперь есть только 100 КБ!

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

Даже когда free() может технически вернуть память в ОС, это может и не сделать. free() необходимо достичь баланса между быстрой эксплуатацией и сохранением памяти. Кроме того, программа, которая уже выделила много памяти, а затем освободила ее, скорее всего, сделает это снова. Веб-сервер должен обрабатывать запрос после запроса после запроса - имеет смысл хранить некоторую "слабую" память, поэтому вам не нужно постоянно запрашивать ОС для памяти.

  • 1
    Что делать, если другим программам требуется память, которую ваша программа держит без необходимости, следовательно, даже если вам больше не понадобятся mallocs, освободите () неиспользуемые области памяти :)
  • 2
    Вы полностью упустили мою точку зрения. Когда вы освобождаете () память, другие программы не могут ее использовать !! (Иногда они могут, особенно если вы освобождаете большие блоки памяти. Но часто они не могут!) Я отредактирую свой пост, чтобы сделать это более понятным.
27

Нет ничего принципиально неправильного в том, что очистка os после запуска приложения.

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

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

  • 0
    О языках сценариев: Python использует refcounting, но имеет GC только для освобождения циклических ссылок. На других языках программист часто вообще избегает явных циклических ссылок, что создает другие проблемы.
  • 0
    Более ранние версии PHP не освобождали память, они просто запускались от начала до конца, увеличиваясь в памяти - после обычно 0,1 секунды времени выполнения сценарий завершал работу, и вся память возвращалась.
19

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

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

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

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

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

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

Там более социальный аспект тоже. При правильном использовании malloc() и free() любой, кто смотрит на ваш код, будет непригоден; вы управляете своими ресурсами. Однако, если вы этого не сделаете, они сразу же заподозрят проблему.

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

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

Умное программирование является гибким и универсальным. Плохое программирование неоднозначно.

  • 0
    Я люблю идею привычки. Я тоже согласен. Если я вижу утечку памяти, я всегда задаюсь вопросом, какой другой угол вырезал кодер. Особенно если это очевидно
  • 0
    Это лучший ответ на сегодняшний день. Я программирую на C ++ уже 5 лет и никогда не писал ни единой утечки памяти. Причина в том, что я не пишу код, который имеет тенденцию к утечке памяти. В хорошем дизайне C ++ вы редко используете new , что сразу устраняет большинство утечек памяти. Только если вы абсолютно обязаны использовать new . Результат этого new должен быть немедленно помещен в умный указатель. Если вы будете следовать этим двум правилам, вы просто никогда не потеряете память (исключая ошибку в библиотеке). Единственный оставшийся случай - циклы shared_ptr , и в этом случае вы должны знать, чтобы использовать weak_ptr .
14

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

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

Теперь предположим, что ваша программа работала с большим объемом данных, но не затронула ее большую часть времени (опять же, веб-браузер - отличный пример). Если у пользователя запущено множество приложений, значительная часть этих данных, скорее всего, была заменена на диск. Если вы просто выходите (0) или возвращаетесь из основного, он немедленно выйдет. Отличный пользовательский интерфейс. Если вы попытаетесь освободить все, вы можете потратить 5 секунд или больше на замену всех данных, только чтобы сразу же выбросить их. Отходы пользовательского времени. Отходы батареи ноутбука. Отходы износа на жестком диске.

Это не просто теоретическое. Всякий раз, когда я нахожусь со слишком большим количеством загруженных приложений, и диск начинает биться, я даже не думаю, что нажимаю "exit". Я добираюсь до терминала так быстро, как могу, и набираю killall -9... потому что я знаю, что "выход" только усугубит его.

  • 5
    Мне нравится эта цитата от Рэймонда Чена: «Здание сносится. Не надо подметать пол и вычищать мусорные баки и стирать доски. И не выстраиваться в очередь на выходе из здания, чтобы каждый мог сдвинуть их внутрь / все, что вы делаете, это заставляете команду по сносу ждать, пока вы закончите эти бессмысленные задачи по уборке ». ( blogs.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683 )
13

Я думаю, что в вашей ситуации ответ может заключаться в том, что все в порядке. Но вам определенно нужно документировать, что утечка памяти является сознательным решением. Вы не хотите, чтобы программист по обслуживанию приходил, ударил свой код внутри функции и называет его миллион раз. Поэтому, если вы принимаете решение о том, что утечка в порядке, вам необходимо задокументировать ее (В БОЛЬШИХ ПИСЬМАХ) для тех, кто, возможно, придется работать над программой в будущем.

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

Но в основном, если утечка памяти является известной величиной, такой как буфер 512 КБ или что-то еще, это не проблема. Если утечка памяти продолжает расти, как и каждый раз, когда вы вызываете вызов библиотеки, ваша память увеличивается на 512 КБ и не освобождается, тогда у вас может быть проблема. Если вы документируете его и контролируете количество раз, когда вызов выполняется, он может быть управляемым. Но тогда вам действительно нужна документация, потому что в то время как 512 не так много, 512 более миллиона звонков - это много.

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

  • 3
    «Но вам определенно необходимо документально подтвердить, что утечка памяти является сознательным решением». Слава богу Лучший момент, сделанный до сих пор.
10

Я уверен, что кто-то может придумать причину сказать "Да", но это не я. Вместо того, чтобы сказать "нет", я скажу, что это не должно быть "да/нет". Есть способы управлять утечками памяти или содержать их, и многие системы имеют их.

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

  • 0
    Это на самом деле пример старения программного обеспечения. Увлекательный предмет изучения.
  • 0
    Автоматическая перезагрузка так часто, да? НАСА, а? (* смотрит на старые установочные компакт-диски Microsoft Windows *) Это многое объясняет ...
8

С одной стороны, я могу рассчитывать количество "доброкачественных" утечек, которые я видел со временем.

Таким образом, ответ - очень квалифицированный да.

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

Я видел, что этот подход был полезен для вещей с очень четко фиксированными учетными записями, такими как требования к краху во время работы с процессорами, и в гораздо меньшей степени в буфере, используемом для хранения состояния singleton /proc/self/maps в Hans Бем консервативный сборщик мусора для C/С++, который используется для обнаружения наборов корней и т.д.

В то время как технически это утечка, оба этих случая ограничены по размеру, а в растущей круговой работе, укравшей дело deque, есть огромный выигрыш в производительности в обмен на ограниченный коэффициент 2 увеличения использования памяти для очередей.

  • 1
    Вы можете использовать указатели опасности, чтобы предотвратить утечку.
8

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

На самом деле, нет необходимости делать вызовы free() или удалять прямо перед выходом. Когда процесс завершается, вся его память возвращается ОС (это, безусловно, относится к POSIX. В других ОС - особенно встраиваемых - YMMV).

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

  • 0
    Позволю себе не согласиться. То есть «утечка памяти сама по себе».
  • 0
    Это не утечка, пока вы не «потеряете» ссылку на объект. Предположительно, если память используется для жизни программы, то она не просочилась. Если ссылка не потеряна до вызова exit (), то это абсолютно не утечка.
Показать ещё 2 комментария
8

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

  • 0
    Не совсем, так как, если он не используется, он просто выгружается. Когда приложение выходит, вся память освобождается.
  • 0
    Пока оно выделено, другие программы не смогут его использовать. Он не будет выгружен, если вы не освободите его.
Показать ещё 3 комментария
6

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

  • Операционная система космического челнока: нет, не допускается утечка памяти.
  • код разработки с быстрой разработкой: исправление всех этих утечек памяти - пустая трата времени.

и существует спектр промежуточных ситуаций.

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

  • 2
    Очень близорукое отношение. Вы в основном говорите, что нет необходимости использовать принципиально правильные методы программирования, пока не будет обнаружено, что дефект вызван этими методами. Проблема заключается в том, что программное обеспечение, написанное с использованием неаккуратных методов, имеет больше дефектов, чем программное обеспечение, которого нет.
  • 1
    Я не верю, что все. А управление памятью сложнее, чем написание чистых методов.
Показать ещё 2 комментария
5

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

Что делать, если вы выделяете некоторую память и используете ее до самой последней строки кода в своем приложении (например, глобальный объект-деконструктор)? До тех пор, пока потребление памяти не будет расти со временем, можно ли доверять ОС, чтобы освободить вашу память для вас, когда ваше приложение завершается (в Windows, Mac и Linux)? Вы даже считали бы это реальной утечкой памяти, если бы память использовалась непрерывно, пока она не была освобождена ОС.

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

Итак, вернемся к оригинальному случаю, это ИМХО отлично в порядке, настолько, что Valgrind, один из самых мощных детекторов утечки, будет обрабатывать такие утечки только по запросу. В Valgrind, когда вы перезаписываете указатель, не освобождая его заранее, он считается утечкой памяти, потому что он скорее повторится и заставит кучу расти бесконечно.

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

  • 0
    Вау ... тот, кто знает, что такое утечка памяти.
5

В этом вопросе контекст - это все. Лично я не могу терпеть утечки, и в своем коде я стараюсь исправить их, если они появятся, но не всегда стоит исправить утечку, и когда люди платят мне к тому моменту, когда я иногда сказал им, что не стоит моей платы за меня, чтобы исправить утечку в их коде. Позвольте мне привести вам пример:

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

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

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

  • 0
    Умный. Тем более, что утечка произошла во время инициализации, что означает, что она не будет накапливаться во время выполнения приложения.
4

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

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

Идеальный ответ: "нет, никогда". Более прагматичный ответ может быть "нет, почти никогда". Очень часто в реальной жизни у вас ограниченное количество ресурсов и времени для решения и бесконечного списка задач. Когда одной из задач является устранение утечек памяти, часто возникает закон уменьшения прибыли. Вы можете устранить 98% всех утечек памяти в приложении через неделю, но оставшиеся 2% могут занять несколько месяцев. В некоторых случаях может быть даже невозможно устранить некоторые утечки из-за архитектуры приложения без серьезного рефакторинга кода. Вы должны взвесить затраты и преимущества устранения оставшихся 2%.

3

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

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

Процесс, который захватывает все больше и больше памяти, не обязательно протекает. До тех пор, пока он способен ссылаться и освобождать эту память, он остается под явным контролем процесса и не просочился. Процесс может быть плохо спроектирован, особенно в контексте системы, где память ограничена, но это не то же самое, что утечка. И наоборот, потеря объема, скажем, 32-байтового буфера по-прежнему является утечкой, хотя количество утечки памяти невелико. Если вы считаете, что это несущественно, подождите, пока кто-то не обернет алгоритм вокруг вашего вызова библиотеки и называет его 10 000 раз.

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

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

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

3

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

Для меня, спрашивая это, как вопрос: "Могу ли я сломать красный свет в 3 часа ночи, когда никто не будет рядом?". Конечно, это может не вызвать никаких проблем в то время, но это даст вам рычаг, чтобы вы сделали то же самое в час пик!

2

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

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

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

2

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

  • 0
    Я думаю, что это требуется тогда.
2

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

КИВ

2

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

Но на ваш вопрос, мой ответ в двух словах находится в производственном коде, да. Во время разработки, нет. Это может показаться обратным, но здесь мои рассуждения:

В описанной ситуации, где память хранится до конца программы, совершенно нормально ее не выпускать. Как только ваш процесс выйдет, ОС все равно очистится. На самом деле, это может заставить пользователя работать лучше: в игре, над которой я работал, программисты думали, что было бы чище освободить всю память до выхода, в результате чего остановка программы займет до половины минуты! Быстрое изменение, которое только что вызвало exit(), заставило процесс немедленно исчезнуть и вернуть пользователя на рабочий стол, где он хотел быть.

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

2

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

Что вы делаете для серверных программ, которые разработаны так, чтобы они не выходили?

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

Утечка этой памяти и пусть программа очистит ее? Нет. Абсолютно нет. Это плохая привычка, которая приводит к ошибкам, ошибкам и большему количеству ошибок.

Очистите себя. Йо мамо не работает здесь больше.

  • 0
    Я работал над серверными программами, которые намеренно используют процессы, а не потоки, поэтому утечки памяти и ошибки сегментации наносят ограниченный ущерб.
  • 0
    Интересный подход. Я был бы немного обеспокоен процессами, которые не могут завершиться и продолжают поглощать память.
2

Это уже обсуждалось ad nauseam. Итог заключается в том, что утечка памяти является ошибкой и должна быть исправлена. Если библиотека сторонних разработчиков утечки памяти, это заставляет задуматься, что еще не так с ним, нет? Если бы вы строили машину, вы бы использовали двигатель, который иногда пропускает масло? В конце концов, кто-то другой сделал двигатель, так что это не ваша вина, и вы не можете это исправить, верно?

  • 0
    Но если у вас был автомобиль с двигателем, в котором иногда происходит утечка масла, вы тратите деньги на его починку или следите за уровнем масла и время от времени доливает его. Ответ зависит от всевозможных факторов.
  • 0
    Это не о владении автомобилем. Это о создании автомобиля. Если вы получаете стороннюю библиотеку с утечками памяти и вам абсолютно необходимо ее использовать, то вы живете с ней. Но если вы пишете систему или библиотеку, вы обязаны убедиться, что она не содержит ошибок.
Показать ещё 1 комментарий
2

Я думаю, вы ответили на свой вопрос. Самым большим недостатком является то, как они мешают обнаружению утечек памяти, но я считаю, что этот недостаток является ОГРОМНЫМ недостатком для определенных типов приложений.

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

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

2

Я согласен с vfilby - это зависит. В Windows мы рассматриваем утечки памяти как относительно серологические ошибки. Но это очень зависит от компонента.

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

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

Итак, если у вас есть утечка - оцените ее влияние двумя способами.

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

Foredecker

  • 0
    3. Влияние на обслуживание программного обеспечения.
2

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

Вот пример, на SunOS в эпоху Sun 3 возникла проблема, если в процессе использовался exec (или более традиционно fork, а затем exec), последующий новый процесс наследовал бы тот же объем памяти, что и родительский, и это могло бы не сокращаться. Если родительский процесс выделил 1/2 гигабайта памяти и не освободил его перед вызовом exec, дочерний процесс начнет использовать тот же 1/2 концерт (хотя он не был выделен). Это поведение лучше всего проявлялось SunTools (их оконная система по умолчанию), которая была похожей на память. Каждое приложение, которое оно создало, было создано через fork/exec и унаследовало SunTools, быстро заполнив пространство подкачки.

2

Я не отвечу.

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

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

2

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

  • 0
    В этом случае влияние утечки памяти меняется, и вам необходимо пересмотреть приоритет устранения утечки.
  • 0
    @Джон: Тебе лучше хотя бы документировать утечку. Даже тогда я бы не стал доверять кому-то, чтобы он не проигнорировал большой красный мигающий комментарий и скопировал и вставил дырявый код. Я предпочитаю не давать кому-то возможность сделать это в первую очередь.
1

Я взял один класс в старшей школе на C, и учитель сказал, что всегда должен быть свободен, когда вы malloc.

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

1

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

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

Хорошее с выходом из приложения:

  • ОС получает один кусок, чтобы освободить, а не многие мелкие куски. Это означает, что выключение происходит намного быстрее. Особенно в Windows с ним медленное управление памятью.

Плохое с просто выходом - это на самом деле две точки:

  • Легко забыть освобождать ресурсы, которые ОС не отслеживает, или что ОС может немного подождать с выпуском. Одним из примеров является сокеты TCP.
  • Программное обеспечение для отслеживания памяти сообщит обо всем, что не освобождено при выходе, как утечка.

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

1

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

Утечка памяти является проблемой, когда утечка увеличивается, когда приложение работает.

1

Похоже, ваше определение "утечка памяти" - это "память, которую я не очищаю". Все современные ОС освободят его при выходе из программы. Однако, поскольку это вопрос на С++, вы можете просто обернуть соответствующую память в соответствующем std::auto_ptr, который будет вызывать удаление, когда он выходит из области видимости.

1

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

Итак, по крайней мере, для ваших товарищей-программистов (а также для себя в будущем), попробуйте как можно скорее их соединить.

1

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

0

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

В общем, обычно неприемлемо оставлять память. Трудно понять все области, в которых будет работать ваш код, а в некоторых случаях это может привести к катастрофе, которая станет катастрофической.

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

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

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

Когда короткоживущая программа создает большие коллекции C++ (например, std::map), по крайней мере 2 распределения на объект. Итерация через эту коллекцию для уничтожения объектов требует реального времени для ЦП и оставляет объект утечкой и должна быть убрана ОС, имеет преимущества в производительности. Счетчик, есть ли какие-то ресурсы, которые не очищаются ОС (например, разделяемая память), а не уничтожая все объекты в вашем коде, открывает риск того, что некоторые из них удерживаются на этих несвободных ресурсах.

Что делать, если библиотека сторонних разработчиков вынудила вас к этой ситуации?

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

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

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

  • Служба во время выключения. Здесь есть компромисс между производительностью времени и правильностью.
  • Сломанный объект, который нельзя уничтожить. Я смог обнаружить поврежденный объект (например, из-за исключения исключений), и когда я пытаюсь уничтожить объект, результатом является зависание (удерживаемый замок).
  • Ошибка проверки памяти.

Служба во время выключения

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

Сломанный объект

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

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

проверка нечеткой проверки

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

  • 1
    В ответах здесь пренебрегают тем, что инициализация трудна, а значит и очистка . Конечно, это может быть оправдано, как перспектива, но есть цена. Текущее отключение создает новые промежуточные состояния, требующие осторожного обращения, в противном случае приводя к гонкам и другим ошибкам. Рассмотрите возможность деинициализации приложения, разделенного на пользовательский интерфейс и рабочий поток, и нуждайтесь в обработке другого конца, которого больше нет. По моему опыту встроенного программирования на основе «голого металла» никто не беспокоится о выключении периферийных устройств и освобождении памяти при отключении питания, кроме случаев, когда это требуется для корректности.
  • 0
    Другими словами, решение не убирать за собой, где оно считается ненужным, может быть не столько признаком лени, сколько компромиссом в инженерном деле.
0

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

0

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

Используйте какой-то умный указатель, который делает это для вас автоматически (например, scoped_ptr из Boost libs)

0

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

0

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

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

В целом, лучше удалить утечки памяти.

0

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

0

Разделение волос возможно: что, если ваше приложение работает в UNIX и может стать зомби? В этом случае память не восстанавливается ОС. Поэтому я говорю, что вам действительно нужно выделить выделение памяти до выхода программы.

0

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

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

0

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

0

Если вы используете его до хвоста вашего main(), это просто не утечка (предполагается, что система защищенной памяти, конечно!).

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

0

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

0

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

Это очень простое правило.. программирование с намерением не иметь утечек делает новые утечки легко заметить. Вы бы продали кому-то автомобиль, который вы знали, что он распылял газ на земле, когда он был выключен?:)

Несколько вызовов if() free() в функции очистки дешевы, почему бы не использовать их?

0

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню