Когда вы выходите из приложения C, автоматически ли освобождается память, выделенная из памяти? - PullRequest
81 голосов
/ 06 февраля 2010

Допустим, у меня есть следующий код C:

int main () {
  int *p = malloc(10 * sizeof *p);
  *p = 42;
  return 0;  //Exiting without freeing the allocated memory
}

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

Ответы [ 9 ]

101 голосов
/ 06 февраля 2010

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

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

40 голосов
/ 06 февраля 2010

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

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

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

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

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

7 голосов
/ 09 ноября 2011

Мои извинения за публикацию так долго после последнего сообщения в этой теме.

Еще один пункт. Не все программы доходят до изящных выходов. Сбои, Ctrl-C и т. Д. Приведут к неконтролируемому завершению программы. Если ваша ОС не освободит вашу кучу, не очистит ваш стек, не удалит статические переменные и т. Д., Вы в конечном итоге выведите систему из строя из-за утечек памяти или еще хуже.

Интересно, что в Ubuntu происходят сбои / сбои, и я подозреваю, что у всех других современных ОС есть проблемы с «обработанными» ресурсами. Сокеты, файлы, устройства и т. Д. Могут оставаться «открытыми», когда программа завершает работу / вылетает. Также рекомендуется закрывать что-либо с помощью «дескриптора» или «дескриптора» как часть вашей очистки перед грациозным выходом.

В настоящее время я разрабатываю программу, которая интенсивно использует сокеты. Когда я застреваю в зависании, мне приходится нажимать ctrl-c, таким образом, прядя свои гнезда. Я добавил std :: vector для сбора списка всех открытых сокетов и обработчика sigaction, который перехватывает sigint и sigterm. Обработчик просматривает список и закрывает сокеты. Я планирую сделать подобную процедуру очистки для использования перед бросками, что приведет к преждевременному завершению.

Кто-нибудь хочет прокомментировать этот дизайн?

6 голосов
/ 06 февраля 2010

То, что здесь происходит ( в современной ОС ), заключается в том, что ваша программа работает внутри собственного «процесса». Это объект операционной системы, наделенный собственным адресным пространством, файловыми дескрипторами и т. Д. Ваши вызовы malloc выделяют память из «кучи» или нераспределенных страниц памяти, которые назначены вашему процессу.

Когда ваша программа заканчивается, как в этом примере, все ресурсы, назначенные вашему процессу, просто перерабатываются / срываются операционной системой. В случае памяти все назначенные вам страницы памяти просто помечаются как «свободные» и перерабатываются для использования другими процессами. Страницы являются понятием более низкого уровня, чем то, что обрабатывает malloc - в результате специфика malloc / free просто стирается, когда все очищается.

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

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

  1. Вы всегда должны программировать, чтобы заботиться о ресурсах, и в C это также означает память. Вы можете в конечном итоге встроить свой код в библиотеку, или он может работать намного дольше, чем вы ожидаете.
  2. Некоторые ОС (более старые и, возможно, некоторые современные встроенные) могут не поддерживать такие жесткие границы процессов, и ваши выделения могут повлиять на адресные пространства других.
4 голосов
/ 06 февраля 2010

Да. ОС очищает ресурсы. Ну ... старые версии NetWare этого не сделали.

Редактировать: Как отметил Сан-Хасинто, безусловно, существуют системы (кроме NetWare), которые этого не делают. Даже в одноразовых программах я стараюсь освободить все ресурсы, чтобы просто сохранить привычку.

2 голосов
/ 06 февраля 2010

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

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

2 голосов
/ 06 февраля 2010

Да, операционная система освобождает всю память после завершения процесса.

0 голосов
/ 18 мая 2012

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

Относительно того, где или когда я обнаружил, что в W98 реальный вопрос был «когда» (я не видел пост, подчеркивающий это). Небольшая шаблонная программа (для ввода MIDI SysEx с использованием различных пробелов malloc) освобождает память в бите WM_DESTROY WndProc, но когда я перенес это в более крупную программу, она вылетает при выходе. Я предположил, что это означало, что я пытался освободить то, что ОС уже освободила во время большей очистки. Если я делал это на WM_CLOSE, а затем вызывал DestroyWindow (), все работало нормально, мгновенный чистый выход.

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

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

0 голосов
/ 06 февраля 2010

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

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