Завершает ли программа восстановление памяти так же, как free ()? - PullRequest
5 голосов
/ 21 апреля 2019

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

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

Кто-нибудь знает, существует ли реальная разница между free () и терминацией в терминах управления памятью, и если да, то как операционная система может по-разному относиться к этим двум?

, например

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

void main() {
    int* mem = malloc(1);
    return 0;
}
void main() {
    int* mem = malloc(1);
    free(mem);
    return 0;
}

Ответы [ 4 ]

6 голосов
/ 21 апреля 2019

Нет, завершение программы, как с exit или abort, не освобождает память так же, как free. Использование free вызывает некоторые действия, которые в конечном итоге не действуют, когда операционная система отбрасывает данные, поддерживаемые malloc и free.

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

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

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

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

С другой стороны, не ясно, можно ли избежать многих звонков на free. Это связано с тем, что освобождение памяти - это не единственное, что должна завершать завершающая программа. Программа может захотеть записать окончательные данные в файлы или отправить окончательные сообщения в сетевые подключения. Кроме того, программа, возможно, не установила весь этот контекст непосредственно. Большинство крупных программ используют слои программного обеспечения, и каждый программный пакет может иметь свой собственный контекст, и зачастую нет никакого способа сообщить другому программному обеспечению: «Я хочу выйти сейчас. Завершите ценный контекст, но пропустите все освобождение памяти ». Таким образом, все желаемые задачи очистки могут быть переплетены с задачами свободной памяти, и, возможно, нет никакого хорошего способа распутать их.

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

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

Сноска

1 Освобождение памяти не означает, что она сразу доступна для других целей. Конкретный результат этого зависит от каждой страницы памяти. Например:

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

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

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

Завершает ли программа восстановление памяти так же, как free?

Не совсем:

  • Завершение программы освобождает память, используемую программой, будь то код программы, данные, стек или куча.Он также освобождает некоторые другие ресурсы, такие как дескрипторы файлов, дескрипторы устройств, сетевые сокеты ... Все это делается эффективно, независимо от того, сколько блоков памяти было выделено с помощью malloc().
  • И наоборот, free() делает блок памяти доступным для дальнейшего использования программой для последующих вызовов malloc() или realloc().В зависимости от размера и реализации кучи, этот освобожденный блок может возвращаться или не возвращаться в ОС для использования другими программами.Также стоит отметить проблему фрагментации, когда небольшие блоки освобожденной памяти могут не использоваться для большего выделения, поскольку они окружены выделенными блоками.Куча C не выполняет упаковку или фрагментацию, она просто объединяет смежные свободные блоки.Освобождение всех выделенных блоков перед выходом из программы может быть полезно для целей отладки, но может быть сложным и занимать много времени, хотя не обязательно для повторного использования памяти системой после завершения программы.
2 голосов
/ 22 апреля 2019

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

могло ли случиться что-то другое между этими двумя короткими программами?

ДА

Я запутался, почему метод free () в C сделал бы что-то отличное от восстановления операционной системыкуча в конце программы.

Операционная система выделяет память в страницах.Менеджеры кучи (такие как реализации malloc / free) выделяют страницы из операционной системы и подразделяют страницы на меньшие выделения.Вызовы free () обычно возвращают память в кучу.Они не возвращают страницы в операционную систему.

2 голосов
/ 21 апреля 2019

free() является функцией управления памятью на уровне пользователя и зависит от реализации malloc, которую вы используете в данный момент. Распределитель пользовательского уровня может поддерживать связанный список фрагментов памяти, а malloc / free возьмет кусок соответствующего размера / вернет его обратно.

exit() Уничтожает адресное пространство и все регионы. Это связано с malloc ed heap, а также с некоторыми другими областями и структурами данных в ядре, используемыми для управления адресным пространством процесса:

Каждое адресное пространство состоит из ряда выровненных по страницам областей памяти, которые используются. Они никогда не пересекаются и представляют собой набор адресов, которые содержат страницы, которые связаны друг с другом в Условия защиты и цели. Эти регионы представлены структура vm_area_struct и примерно аналогичны Структура vm_map_entry в BSD. Для ясности, регион может представлять куча процесса для использования с malloc (), отображаемым в память файлом, таким как общая библиотека или блок анонимной памяти, выделенный с ММАП (). Страницы для этого региона, возможно, еще должны быть выделены, активный и резидент или был выгружен

Ссылка: https://www.kernel.org/doc/gorman/html/understand/understand007.html

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