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


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

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

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

9 77

9 ответов:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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