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

231

Допустимо ли когда-нибудь иметь утечку памяти в вашем приложении на C или C ++?

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

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

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

наполнения
источник
51
Если потребление памяти не растет со временем, это не утечка.
mpez0
4
Большинство приложений (включая все программы .NET) имеют как минимум несколько буферов, которые выделяются один раз и никогда не освобождаются явно. Поэтому определение mpez0 более полезно.
Бен Фойгт
2
Да, если у вас бесконечная память.
пользователь
«Доброкачественная» утечка (если есть такая вещь) не является ложным срабатыванием - это утечка, которая была очень правильно обнаружена. Обнаружение утечек, даже для утечек, которые лично вы не чувствуете, как исправить, является основной причиной существования течеискателя.
Цао
1
@ mpez0 "Если потребление памяти не растет со временем, это не утечка"? Это не определение утечки памяти. Утечка - это утечка памяти, что означает, что она не была освобождена, и вы больше не имеете к ней никакого отношения, поэтому вы никогда не сможете снова ее освободить. Растет это или нет, не имеет значения.
Меки

Ответы:

330

Нет.

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

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

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

Это похоже на предупреждения компилятора - будет ли это фатальным для моего конкретного приложения? Может быть нет.

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

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

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

-

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

JohnMcG
источник
57
Правда и не правда одновременно. В конечном итоге большинство из нас являются наемными рабами, и любое стремление к мастерству должно отойти на второй план к требованиям бизнеса. Если эта сторонняя библиотека имеет утечку и экономит 2 недели работы, возможно, существует экономическое обоснование для ее использования и т. Д.
Cervo
3
В любом случае, я бы использовал библиотеку, если бы это было чем-то, что мне было нужно, и не было достойных альтернатив, но я бы сообщал об ошибке с сопровождающими.
tloach
7
Хотя я лично отвечу точно так же, есть программы, которые почти не освобождают память. Причина в том, что они а) предназначены для работы на ОС, которые освобождают память, и б) предназначены для работы не очень долго. Редкие ограничения для программы действительно, но я принимаю это как совершенно допустимое.
2
Чтобы добавить некоторые причины для ранней проверки: когда ваши инструменты отладки затоплены «доброкачественными» утечками, как вы собираетесь найти «настоящую»? Если вы добавляете пакетную функцию, и вдруг ваша утечка 1K / час становится 1K / секунду?
peterchen
5
Хм это "не утечка памяти" "идеально"?
JohnMcG
80

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

Джим С
источник
12
Технически, утечка - это выделенная память, и все ссылки на нее потеряны. Не освобождать память в конце просто лень.
Мартин Йорк,
17
Если у вас есть разовая утечка памяти 4 ГБ, это проблема.
Джон Диблинг
21
Не имеет значения, растет он или нет. Другие программы не могут использовать память, если она у вас есть.
Билл Ящерица
8
> Другие программы не могут использовать память, если она у вас есть. Что ж, ОС всегда может поменять вашу память на диск и позволить другим приложениям использовать оперативную память, которой вы не воспользовались.
Макс Либберт
4
Если программа очень недолговечная, то утечка может быть не такой уж плохой. Кроме того, хотя это и НЕ идеал, подкачка не так дорога, как это делают некоторые здесь, потому что программа не интересуется этой памятью (и, следовательно, не будет постоянно менять местами) - если, конечно, у вас нет GC ...
Арафангион
79

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

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

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

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

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

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

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

Чарли Мартин
источник
Теперь рассмотрим несколько десятков из этих распределений. Теперь рассмотрим необходимость переместить «основное» тело в процедуру, которая вызывается несколько раз. Наслаждаться. - Я согласен с мнением, что в этом сценарии такая большая проблема, но сценарии меняются. Как говорится, всегда пишите код, как будто парень, который его поддерживает, знает, где вы живете.
peterchen
2
Дело в том, что память, которая распределена по malloc'у и удерживается до тех пор, пока программа не вызовет _exit (), не будет "утечка".
Чарли Мартин
1
Это утечка памяти, и это может повредить вашу программу. Распределение в будущем может потерпеть неудачу из-за этого процесса, потому что я уверен, что вы проверяете, что malloc возвратил не nil везде. из-за чрезмерного использования памяти, например, во встроенной ситуации, когда памяти мало, это может быть разницей между жизнью и смертью.
MikeJ
10
Майк, это просто неправда. В совместимой среде C завершение main освобождает все ресурсы процесса. Во встроенной среде, как вы описываете, вы можете увидеть эту ситуацию, но у вас не будет основной. Теперь я допускаю, что могут быть дефектные встроенные среды, для которых это не будет правдой, но потом я видел дефектные среды, которые тоже не могли правильно справиться с + =.
Чарли Мартин
3
Да, теперь вы обнаружили, что если у вас mallocслишком много памяти, это плохо. Это все еще не утечка . Это не утечка до тех пор, пока не mallocбудет потеряна ссылка на память.
Чарли Мартин
39

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

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

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

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

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

vfilby
источник
Я не знаю, читали ли вы весь мой вопрос или нет. Я говорю, что память используется до самого конца приложения. Это не растет со временем. Единственное нет нет, это то, что нет вызова для освобождения / удаления.
Полнота
2
Тогда это на самом деле не утечка памяти. Утечка памяти - это небольшие объемы неиспользуемой, но несвободной памяти, которая с течением времени увеличивается. То, о чем вы говорите, это капля памяти. Не беспокойтесь, если ваша капля не очень большая.
vfilby
«Если это не вызывает проблемы, это действительно имеет значение?» Нет, это не имеет значения вообще. Я хотел бы, чтобы больше людей получили это вместо того, чтобы стать религиозными.
Полнота
2
@John: Обычно это не вопрос ленивых разработчиков, а вопрос развития программного обеспечения. Мы все совершаем ошибки, ошибки - наша профессия; мы делаем их, мы исправляем их, это то, что мы делаем. Это всегда баланс между первоначальной стоимостью и долгосрочным обслуживанием, этот баланс никогда не бывает простым.
vfilby
1
Джон, я на 100% согласен с тобой. Имбум. Вопрос почти в том, «сколько ты принимаешь». Неаккуратный неаккуратный .. Как насчет того, чтобы оставить креветку позади вашего монитора. вонь воняет. Каждый раз, когда мы проходим, наша индустрия немного прогибается. Если вы знаете, что есть утечка, и вы знаете, что вызвали ее, то вы должны это исправить.
baash05
37

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

R .. GitHub СТОП, ПОМОГАЯ ЛЬДУ
источник
5
Мне нравится эта цитата от Рэймонда Чена: «Здание сносится. Не надо подметать пол и вычищать мусорные баки и стирать доски. И не выстраиваться в очередь на выходе из здания, чтобы каждый мог сдвинуть их внутрь / все, что вы делаете, это заставляете команду по сносу ждать, пока вы закончите эти бессмысленные задачи по уборке ». ( blogs.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683 )
Андреас Магнуссон,
11

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

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

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

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

Билл Ящерица
источник
Не совсем, так как, если он не используется, он просто выгружается. Когда приложение выходит, вся память освобождается.
Затмение
Пока он выделен, другие программы не смогут его использовать. Он не будет выгружен, если вы не освободите его.
Билл Ящерица
Конечно, так и будет - вот что такое виртуальная память. Вы можете иметь 1 ГБ фактической оперативной памяти, и при этом иметь 4 процесса, каждый из которых полностью выделяет 2 ГБ виртуальной памяти (при условии, что ваш файл подкачки достаточно большой).
Затмение
Конечно, вы получите неприятные проблемы с подкачкой, если каждый из этих процессов активно использует всю эту память.
Затмение
Хорошо, я понимаю, о чем ты сейчас говоришь. Если вы освободите память, которую не используете, вы уменьшите потребность в подкачке. Если вы оставите его выделенным, ваше приложение все равно сохранит его, когда оно будет перенесено обратно.
Bill the Lizard
8

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

Так что ответ очень квалифицированный да.

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

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

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

Эдвард КМЕТТ
источник
1
Вы можете использовать указатели опасности, чтобы предотвратить утечку.
Деми
8

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

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

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

nsayer
источник
Позволю себе не согласиться. То есть «память течь сама по себе».
Конрад Рудольф
Это не утечка, пока вы не «потеряете» ссылку на объект. Предположительно, если память используется для жизни программы, то она не просочилась. Если ссылка не потеряна до вызова exit (), то это абсолютно не утечка.
nsayer
Amiga DOS был последним O / SI, на который не обращали внимания после процессов. Однако помните, что разделяемую память System V IPC можно оставить, даже если ее не использует ни один процесс.
Джонатан Леффлер
Palm не освобождает память, «просочилась» до тех пор, пока вы не проклянетесь. это пришло хорошо после амиги. Я запускал приложения на моем эмуляторе ладони, у которых были утечки ... Никогда они не пробивались к моей настоящей ладони.
baash05
6

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

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

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

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

Дастин Гетц
источник
2
Очень близорукое отношение. Вы в основном говорите, что нет необходимости использовать принципиально правильные методы программирования, пока не будет обнаружено, что дефект вызван этими методами. Проблема в том, что программное обеспечение, написанное с использованием неаккуратных методов, имеет больше дефектов, чем программное обеспечение, которого нет.
Джон Диблинг
1
Я не верю, что все. А управление памятью сложнее, чем написание чистых методов.
Дастин Гетц
1
Дастин, очевидно, работает в реальном мире, как и большинство из нас, где мы постоянно работаем против безумных сроков, чтобы не отставать от конкурентов. Поэтому работа с ошибками должна быть прагматичной. Тратя слишком много времени на неважные ошибки в неважных программах, вы не добьетесь успеха.
Wouter van Nifterick
Проблема с таким отношением: когда вы начинаете устранять утечки? «Хорошо, это силовая установка, но это просто уголь, а не уран. Зачем здесь устранять утечки?» - В реальном мире я узнал, что если ты не поступаешь правильно с самого начала, то все время этого просто не происходит. Такое отношение порождает проекты, которые завершаются на 99% через две недели и остаются таковыми в течение двух месяцев.
peterchen
5

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

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

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

Джон Диблинг
источник
5

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

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

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

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

Луи Гербарг
источник
Умная. Тем более, что утечка произошла во время инициализации, что означает, что она не будет накапливаться во время выполнения приложения.
Деми
5

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

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

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

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

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

Blaisorblade
источник
Вау ... тот, кто знает, что такое утечка памяти.
Саймон Бьюкен
4

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

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

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

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

  1. К вашему программному обеспечению и опыту вашего пользователя.
  2. Для системы (и пользователя) с точки зрения экономии ресурсов системы.
  3. Влияние исправления на техническое обслуживание и надежность.
  4. Вероятность возникновения регрессии в другом месте.

Foredecker

Foredecker
источник
3. Влияние на обслуживание программного обеспечения.
peterchen
3

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

Для меня задавать вопросы - это все равно что задавать вопросы «Могу ли я выключить красный свет в 3 часа утра, когда никого нет рядом?». Ну, конечно, это может не вызвать никаких проблем в это время, но это даст вам рычаг, чтобы сделать то же самое в час пик!

Ather
источник
3

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

KIV


источник
3

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

Beep Beep
источник
3

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

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

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

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

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

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

Компонент 10
источник
2

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

Санджая Р
источник
2

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

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

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

Кори Трагер
источник
2

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

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

Я отвечу нет.

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

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

Конрад Рудольф
источник
2

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

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

плинтус
источник
2

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

Дима
источник
Но если у вас был автомобиль с двигателем, в котором иногда течет масло, вы тратите деньги на его починку или следите за уровнем масла и время от времени доливает его. Ответ зависит от всевозможных факторов.
тонкий
Это не о владении автомобилем. Это о создании автомобиля. Если вы получаете стороннюю библиотеку с утечками памяти, и вам абсолютно необходимо ее использовать, то вы живете с ней. Но если вы пишете систему или библиотеку, вы обязаны убедиться, что она не содержит ошибок.
Дима
+1 относитесь к нему как к любому другому багу. (Это не означает «исправить мгновенно» в моей книге, но наверняка «нужно исправить»)
peterchen
2

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

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

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

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

Убери за собой. Эй, мама, здесь больше не работает.

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

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

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

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

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

Энно
источник