Когда вы выходите из приложения C, автоматически ли освобождается память malloc-ed?

Скажем, у меня есть следующий код C:

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

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

Ответ 1

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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

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

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

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

Ответ 9

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

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

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

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