Скажем, у меня есть следующий код C:
int main () {
int *p = malloc(10 * sizeof *p);
*p = 42;
return 0; //Exiting without freeing the allocated memory
}
Когда я компилирую и выполняю эту программу на C, то есть после выделения некоторого места в памяти, будет ли выделенная мной память по-прежнему выделяться (т.е. в основном занимать место) после того, как я выйду из приложения и процесс завершится?
c
memory-management
Андреас Греч
источник
источник
Ответы:
Это зависит от операционной системы. Большинство современных (и всех основных) операционных систем освобождают память, не освобожденную программой, при ее завершении.
Полагаться на это - плохая практика, и лучше освободить ее явно. Проблема не только в том, что ваш код плохо выглядит. Вы можете решить, что хотите интегрировать свою небольшую программу в более крупную и длительную. Затем через некоторое время вам придется часами отслеживать утечки памяти.
Использование функции операционной системы также делает код менее переносимым.
источник
Как правило, современные операционные системы общего назначения очищаются после завершения процессов . Это необходимо, поскольку в качестве альтернативы система может со временем терять ресурсы и требовать перезагрузки из-за программ, которые плохо написаны или просто имеют редко встречающиеся ошибки, приводящие к утечке ресурсов.
В любом случае, если ваша программа явно освобождает свои ресурсы, это может быть хорошей практикой по разным причинам, например:
Однако есть причина не освобождать память: эффективное завершение работы . Например, предположим, что ваше приложение содержит большой кеш в памяти. Если при выходе он проходит через всю структуру кеша и освобождает его по частям, это бесполезно и тратит ресурсы. Особенно рассмотрите случай, когда страницы памяти, содержащие ваш кэш, были переставлены на диск операционной системой; Обходя структуру и освобождая ее, вы возвращаете все эти страницы в память сразу , тратя много времени и энергии без какой-либо реальной пользы и, возможно, даже вызывая замену других программ в системе!
В качестве связанного примера есть высокопроизводительные серверы, которые работают, создавая процесс для каждого запроса, а затем завершая его работу; это означает, что им даже не нужно отслеживать выделение памяти и вообще никогда не выполнять освобождение или сборку мусора, поскольку все просто исчезает обратно в свободную память операционной системы в конце процесса. (То же самое можно сделать в процессе с использованием специального распределителя памяти, но это требует очень тщательного программирования; по сути, создание собственного понятия «легковесные процессы» в процессе ОС.)
источник
Приношу свои извинения за то, что разместил так долго после последнего сообщения в этой теме.
Еще один момент. Не все программы позволяют корректно завершать работу. Сбои, клавиши Ctrl-C и т. Д. Приведут к неконтролируемому завершению программы. Если ваша ОС не освобождает кучу, не очищает стек, не удаляет статические переменные и т. Д., Вы в конечном итоге вылетаете из-за утечки памяти или того хуже.
Интересно, что сбои / прерывания в Ubuntu, и я подозреваю, что во всех других современных ОС действительно есть проблемы с «обрабатываемыми» ресурсами. Сокеты, файлы, устройства и т. Д. Могут оставаться «открытыми», когда программа завершается / вылетает. Это так. также хорошая практика - закрыть что-либо с помощью «дескриптора» или «дескриптора» как часть вашей очистки перед плавным выходом.
В настоящее время я разрабатываю программу, которая активно использует сокеты. Когда я застреваю в зависании, я должен выйти из него ctrl-c, таким образом скручивая мои сокеты. Я добавил std :: vector для сбора списка всех открытых сокетов и обработчик sigaction, который улавливает sigint и sigterm. Обработчик просматривает список и закрывает сокеты. Я планирую сделать аналогичную процедуру очистки для использования перед броском, что приведет к преждевременному завершению.
Кто-нибудь хочет прокомментировать этот дизайн?
источник
Что здесь происходит ( в современной ОС ), так это то, что ваша программа работает внутри своего собственного «процесса». Это объект операционной системы, наделенный собственным адресным пространством, файловыми дескрипторами и т. Д. Ваши
malloc
вызовы выделяют память из «кучи» или нераспределенные страницы памяти, назначенные вашему процессу.Когда ваша программа завершается, как в этом примере, все ресурсы, назначенные вашему процессу, просто перерабатываются / уничтожаются операционной системой. В случае с памятью все назначенные вам страницы памяти просто помечаются как «свободные» и используются для использования другими процессами. Страницы представляют собой концепцию более низкого уровня, чем то, что обрабатывает malloc - в результате все особенности malloc / free просто стираются, поскольку все это очищается.
Это моральный эквивалент того, что когда вы закончили использовать свой ноутбук и хотите отдать его другу, вы не утруждаетесь удалением каждого файла по отдельности. Вы просто форматируете жесткий диск.
Все это говорит о том, что, как отмечают все другие респонденты, полагаться на это не является хорошей практикой:
источник
Да. ОС очищает ресурсы. Ну ... старые версии NetWare этого не сделали.
Изменить: как указал Сан-Хасинто, безусловно, существуют системы (помимо NetWare), которые этого не делают. Даже в одноразовых программах я стараюсь освободить все ресурсы, чтобы сохранить эту привычку.
источник
Да, операционная система освобождает всю память по завершении процесса.
источник
malloc
можно только пообещать, что C будет делать с памятью; По замыслу C ничего не гарантирует в отношении поведения за пределами самого C. Если приложение неожиданно умирает, любые обещания, сделанные библиотекой времени выполнения, являются недействительными, поскольку оно больше не живо, чтобы соответствовать им.Это зависит от того, операционные системы обычно очищают его за вас, но если вы работаете, например, над встроенным программным обеспечением, оно может не быть выпущено.
Просто убедитесь, что вы освободили его, это может сэкономить вам много времени позже, когда вы, возможно, захотите интегрировать его в большой проект.
источник
Это действительно зависит от операционной системы, но для всех операционных систем, с которыми вы когда-либо столкнетесь, выделение памяти исчезнет, когда процесс завершится.
источник
Я считаю, что прямое освобождение лучше всего. Неопределенное поведение - худшая вещь, поэтому, если у вас есть доступ, пока он все еще определен в вашем процессе, сделайте это, есть много веских причин, по которым люди его называют.
Что касается того, где и обнаружил ли я это в W98, реальный вопрос был в том, «когда» (я не видел сообщения, подчеркивающего это). Небольшая программа-шаблон (для ввода MIDI SysEx с использованием различных пространств malloc'd) освободила бы память в бите WM_DESTROY WndProc, но когда я трансплантировал это в более крупную программу, она вылетела при выходе. Я предположил, что это означает, что я пытаюсь освободить то, что ОС уже освободила во время большой очистки. Если бы я сделал это на WM_CLOSE, а затем вызвал бы DestroyWindow (), все работало бы нормально, мгновенный чистый выход.
Хотя это не совсем то же самое, что и буферы MIDI, есть сходство в том, что лучше всего сохранить процесс без изменений, полностью очистить, а затем выйти. При небольших объемах памяти это очень быстро. Я обнаружил, что многие маленькие буферы работают быстрее и очищаются, чем меньшее количество больших.
Могут существовать исключения, как кто-то сказал, избегая извлечения больших блоков памяти обратно из файла подкачки на диске, но даже это можно свести к минимуму, сохраняя больше и меньше выделенных пространств.
источник