Во многих книгах и учебных пособиях я слышал, как подчеркивается практика управления памятью, и чувствовал, что некоторые загадочные и ужасные вещи могут произойти, если я не освобожу память после того, как использую ее.
Я не могу говорить о других системах (хотя для меня разумно предположить, что они применяют подобную практику), но по крайней мере в Windows ядро в основном гарантированно очищает большинство ресурсов (за исключением нечетного числа), используемых программа после завершения программы. Что включает в себя кучу памяти, среди прочего.
Я понимаю, почему вы захотите закрыть файл после того, как вы его используете, чтобы сделать его доступным для пользователя, или почему вы хотите отключить сокет, подключенный к серверу, чтобы сэкономить пропускную способность, но это кажется глупым должен микроуправлять ВСЕМ вашей памятью, используемой вашей программой.
Теперь я согласен, что этот вопрос является широким, поскольку то, как вы должны обращаться с вашей памятью, основано на том, сколько памяти вам нужно и когда вам это нужно, поэтому я ограничу сферу этого вопроса следующим образом: если мне нужно использовать часть памяти на протяжении всей жизни моей программы, действительно ли необходимо освобождать ее непосредственно перед завершением программы?
Изменить: вопрос, предложенный в качестве дубликата, был характерен для семейства операционных систем Unix. В его верхнем ответе даже указан инструмент, специфичный для Linux (например, Valgrind). Этот вопрос предназначен для охвата большинства «обычных» не встроенных операционных систем, а также того, почему стоит или не рекомендуется освобождать память, которая необходима на протяжении всей жизни программы.
источник
Ответы:
Это не обязательно, но может иметь свои преимущества (а также некоторые недостатки).
Если программа выделяет память один раз во время выполнения и в противном случае никогда не освободит ее до завершения процесса, может быть разумным подходом не освобождать память вручную и полагаться на ОС. На каждой современной операционной системе, которую я знаю, это безопасно, в конце процесса вся выделенная память надежно возвращается в систему.
В некоторых случаях, не очистка выделенной памяти явно может даже быть заметно быстрее, чем очистка.
Однако, освобождая всю память в конце выполнения явно,
Продолжительность жизни программ может измениться. Возможно, ваша программа сегодня - это небольшая утилита командной строки, с типичным временем жизни менее 10 минут, и она выделяет память порциями по несколько килобайт каждые 10 секунд - поэтому не нужно вообще освобождать выделенную память до завершения программы. Позже программа изменяется и получает расширенное использование как часть серверного процесса со сроком службы в несколько недель - поэтому не освобождается промежуточная неиспользуемая память больше не вариант, иначе ваша программа со временем начинает поглощать всю доступную серверную память , Это означает, что вам придется просмотреть всю программу и впоследствии добавить освобождающий код. Если вам повезет, это простая задача, в противном случае это может быть настолько сложно, что высоки шансы, что вы пропустите место. И когда вы окажетесь в такой ситуации, вам будет жаль, что вы добавили «бесплатно»
В целом, написание кода выделения и связанного освобождения всегда попарно считается «хорошей привычкой» для многих программистов: делая это всегда, вы уменьшаете вероятность забывания кода освобождения в ситуациях, когда память должна быть освобождена.
источник
main
.Освобождение памяти в конце выполнения программы - просто трата процессорного времени. Это похоже на уборку дома перед тем, как убрать его с орбиты.
Однако иногда то, что было краткосрочной программой, может стать частью гораздо более длительной. Тогда освобождение материала становится необходимым. Если это не задумывалось хотя бы до некоторой степени, то это может потребовать существенной переделки.
Одним из разумных решений для этого является «talloc», который позволяет вам загружать память и затем отбрасывать их все одним вызовом.
источник
free
обычно намного быстрее чемmalloc
.Вы можете использовать язык со сборщиком мусора (такой как Scheme, Ocaml, Haskell, Common Lisp и даже Java, Scala, Clojure).
(В большинстве языков GC-й изд, нет никакого способа , чтобы явно и вручную свободная память Иногда, некоторые значения могут быть! Завершено , например, GC и выполнение система закроет значение дескриптора файла , когда это значение недостижимо, но это не конечно, ненадежно, и вы должны вместо этого явно закрыть свои файловые дескрипторы, так как завершение никогда не гарантируется)
Вы также можете, для вашей программы, написанной на C (или даже C ++) использовать консервативный сборщик мусора от Boehm . Затем вы бы заменили все ваши
malloc
наGC_malloc
и не беспокоиться оfree
-ing любой указатель. Конечно, вы должны понимать плюсы и минусы использования Boehm GC. Читайте также руководство GC .Управление памятью является глобальным свойством программы. В некотором смысле это (и жизнеспособность некоторых данных) является не композиционным и не модульным, поскольку является целым свойством программы.
Наконец, как указывали другие,
free
хорошая практика - выделять кучу выделенной зоны памяти C - хорошая практика. Для игрушечной программы, не выделяющей много памяти, вы даже можете решить вообще не использоватьfree
память (поскольку после завершения процесса его ресурсы, включая виртуальное адресное пространство , будут освобождены операционной системой).Нет, тебе не нужно этого делать. И многие программы реального мира не беспокоят освобождение некоторой памяти, которая необходима на протяжении всего срока службы (в частности, компилятор GCC не освобождает часть своей памяти). Однако, когда вы делаете это (например, вы не беспокоитесь о
free
каком-то конкретном фрагменте данных, динамически размещаемых на Си ), вы лучше прокомментируете этот факт, чтобы облегчить работу будущих программистов над тем же проектом. Я склонен рекомендовать, чтобы объем несвободной памяти оставался ограниченным и обычно был относительно небольшим по отношению к общему количеству используемой памяти кучи.Обратите внимание, что система
free
часто не освобождает память для ОС (например, вызывая munmap (2) в системах POSIX), но обычно помечает зону памяти как пригодную для повторного использования в будущемmalloc
. В частности, виртуальное адресное пространство (например, как видно/proc/self/maps
из Linux, см. Proc (5) ....) может не уменьшаться послеfree
(следовательно, утилиты любятps
илиtop
сообщают о том же объеме используемой памяти для вашего процесса).источник
В этом нет необходимости , так как если вы этого не сделаете, вы не сможете выполнить свою программу должным образом. Тем не менее, есть причины, по которым вы можете выбрать, если есть шанс.
Один из самых мощных случаев, с которыми я сталкиваюсь (снова и снова), - это то, что кто-то пишет небольшой фрагмент кода моделирования, который выполняется в их исполняемом файле. Они говорят: «Мы бы хотели, чтобы этот код был интегрирован в симуляцию». Затем я спрашиваю их, как они планируют переинициализироваться между пробегами Монте-Карло, и они смотрят на меня безучастно. «Что вы имеете в виду, повторная инициализация? Вы просто запускаете программу с новыми настройками?»
Иногда чистая очистка значительно облегчает использование вашего программного обеспечения. В случае многих примеров вы предполагаете, что вам никогда не нужно что-то очищать, и вы делаете предположения о том, как вы можете обрабатывать данные и их срок службы в соответствии с этими предположениями. Когда вы переходите в новую среду, где эти предположения не действительны, целые алгоритмы могут перестать работать.
В качестве примера того, как странные вещи могут происходить, посмотрите, как управляемые языки справляются с завершением в конце процессов, или как C # решает программную остановку доменов приложений. Они связывают себя в узлы, потому что есть предположения, которые проваливаются сквозь трещины в этих крайних случаях.
источник
Игнорирование языков, где вы все равно не освобождаете память вручную ...
То, что вы сейчас считаете «программой», может в какой-то момент стать просто функцией или методом, который является частью более крупной программы. И тогда эта функция может вызываться несколько раз. И тогда память, которую вы должны были «освободить вручную», станет утечкой памяти. Это, конечно, решение суда.
источник
Потому что очень вероятно, что через некоторое время вы захотите изменить свою программу, возможно, интегрировать ее с чем-то другим, запустить несколько экземпляров последовательно или параллельно. Тогда потребуется вручную освободить эту память - но вы больше не будете помнить обстоятельства, и вам потребуется гораздо больше времени, чтобы заново понять вашу программу.
Делайте вещи, пока ваше понимание о них еще свежо.
Это небольшие инвестиции, которые могут принести большую прибыль в будущем.
источник
Нет, это не обязательно, но это хорошая идея.
Вы говорите, что чувствуете, что «загадочные и ужасные вещи произойдут, если я не освобожу память после того, как использую ее».
С технической точки зрения, единственным последствием этого является то, что ваша программа будет продолжать потреблять больше памяти, пока не будет достигнут жесткий предел (например, ваше виртуальное адресное пространство исчерпано) или производительность станет неприемлемой. Если программа вот-вот завершится, все это не имеет значения, поскольку процесс фактически прекращает свое существование. «Таинственные и ужасные вещи» связаны исключительно с психическим состоянием разработчика. Поиск источника утечки памяти может быть абсолютным кошмаром (это преуменьшение), и для написания кода без утечек требуется много навыков и дисциплины. Рекомендуемый подход к развитию этого навыка и дисциплины - всегда освобождать память, когда она больше не нужна, даже если программа заканчивается.
Конечно, это дает дополнительное преимущество, так как ваш код может быть повторно использован и адаптирован, как уже говорили другие.
Однако есть по крайней мере один случай, когда лучше не освобождать память непосредственно перед завершением программы.
Рассмотрим случай, когда вы сделали миллионы небольших выделений, и они в основном были перенесены на диск. Когда вы начинаете все освобождать, большую часть вашей памяти необходимо вернуть обратно в оперативную память, чтобы получить доступ к бухгалтерской информации только для немедленного сброса данных. Это может заставить программу занять несколько минут, чтобы выйти! Не говоря уже о том, что в это время на диск и физическую память оказывалось большое давление. Если физической памяти не хватает для начала (возможно, программа закрывается, потому что другая программа отнимает много памяти), то отдельные страницы могут нуждаться в подкачке и выгрузке несколько раз, когда необходимо освободить несколько объектов из та же страница, но не освобождается последовательно.
Если вместо этого программа просто прерывается, ОС просто отбрасывает всю память, которая была перенесена на диск, что почти мгновенно, потому что она вообще не требует доступа к диску.
Важно отметить, что в языке OO вызов деструктора объекта также заставит обменяться памятью; если вам нужно сделать это, вы можете также освободить память.
источник
Основными причинами очистки вручную являются следующие: менее вероятно, что вы допустите истинную утечку памяти за блок памяти, который будет просто очищен при выходе, иногда вы будете обнаруживать ошибки в распределителе только при обходе всей структуры данных в освободить его, и вы будете иметь гораздо меньшую головную боль , если вы когда - либо реорганизовать так , что какой - то объект действительно нужно получить освобождаться до выхода из программы.
Основными причинами, по которым не нужно выполнять очистку вручную, являются: производительность, производительность, производительность и возможность некоторой ошибки «два раза бесплатно» или «использование после освобождения» в ненужном коде очистки, которая может превратиться в ошибку сбоя или безопасность эксплуатируют.
Если вы заботитесь о производительности, вы всегда хотите профилировать, чтобы узнать, где вы тратите все свое время, а не гадать. Возможный компромисс - заключить необязательный код очистки в условный блок, оставить его во время отладки, чтобы получить преимущества написания и отладки кода, а затем, если и только если вы эмпирически определили, что это слишком много накладные расходы, скажите компилятору пропустить его в вашем конечном исполняемом файле. А задержка закрытия программы почти по определению едва ли когда-нибудь на критическом пути.
источник