Может ли блок памяти, выделенный с помощью оператора new/malloc, сохраняться после завершения выполнения программы?

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

Этот вопрос пришёл мне в голову, когда я читал о том, как принудительно использовать delete/free соответственно, когда речь заходит о динамическом распределении памяти в C/C++. Я думал, что если выделение памяти сохранится после завершения выполнения моей программы, то да, это обязательно; в противном случае, почему я должен беспокоиться об освобождении выделенного пространства? Разве ОС не собирается автоматически освобождать ее при завершении процесса? Насколько я прав? Мой вопрос в том, что может

int *ip = new int(8);

сохраняться после окончания моей программы?

9 ответов

Решение

Краткий ответ: Нет.

Длинный ответ: Нет. C++ никогда не сохранит память, если вы не сделаете работу, чтобы сделать это. Причина освобождения памяти заключается в следующем:

Если вы не освобождаете память, а продолжаете выделять ее, в какой-то момент у вас кончится. Как только вы закончите, почти все может случиться. В Linux, возможно, OOM killer активирован, и ваш процесс убит. Может быть, ОС выдает страницы полностью на диск. Может быть, вы дадите Windows окно синего экрана, если вы используете достаточно памяти. Это почти можно считать неопределенным поведением. Кроме того, если вы теряете память, она просто находится там, не используется, не выпущена, и никто не может использовать ее, пока ваш процесс не завершится.

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

РЕДАКТИРОВАТЬ: стандарты C и C++ даже не дают гарантии, что память будет очищена ОС после завершения. Многие операционные системы и компиляторы могут, но нет никаких гарантий. Несмотря на это, все основные настольные и мобильные операционные системы (за исключением, вероятно, DOS и некоторых очень старых встроенных систем) очищают память процессов после нее.

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

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

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

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

С учетом вышесказанного все равно будет хорошей идеей освободить память в любом случае: если ваша программа много использует динамическую память, вам почти наверняка потребуется запустить профилировщик памяти для проверки утечек памяти. Профилировщик расскажет вам о блоках, которые вы не освободили в конце, и вам нужно будет помнить, чтобы игнорировать их. Гораздо лучше держать число утечек равным нулю по той же причине, по которой хорошо исключать 100% предупреждений вашего компилятора.

1) Освободите свою память, когда вы запросите, если с кучи. Утечки памяти никогда не бывают полезными. Если это не повредит вам сейчас, скорее всего, это будет в будущем.

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

Любая хорошая ОС должна очистить все ресурсы при выходе из процесса; принцип "всегда свободен, что вы выделили" хорош для двух вещей:

  1. Если ваша программа теряет память, но никогда не завершает работу (демоны, серверы, ...), непрерывная утечка памяти будет сильно расходовать ОЗУ.

  2. Вы не должны откладывать освобождение всей памяти до тех пор, пока ваша программа не завершится (как иногда делает Firefox - заметили, сколько времени требуется для ее выхода?) - смысл в том, чтобы минимизировать время, на которое вы выделили память; даже если ваша программа продолжает работать, вы должны сразу же освободить выделенную оперативную память после того, как закончите с ней.

Если вы абсолютно уверены, что вам никогда не понадобится освобождать память во время жизни программы, технически можно пропустить освобождение / удаление. Операционные системы, такие как Linux, Windows и т. Д., Освободят выделенную память после завершения процесса. Но на практике вы почти никогда не можете предположить, что выделенная вами память не должна быть освобождена в течение времени жизни процесса. Принимая во внимание возможность повторного использования кода, удобство обслуживания и расширяемость, рекомендуется всегда высвобождать все, что вы выделяете в соответствующем месте.

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

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

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

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

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

Вы должны беспокоиться об этом, потому что представьте, что вы выделяете много памяти во многих местах и ​​НЕ освобождаете ее. После выделения памяти она занимает часть памяти, которая больше не может быть выделена. Это приведет к тому, что объем доступной памяти будет уменьшаться и уменьшаться с каждым разом, поскольку вы не можете ее освободить. В какой-то момент память будет исчерпана. Даже если память освобождается при завершении программы, представьте, что ваша программа работает несколько недель подряд, постоянно выделяя память, но никогда не освобождая ее. Память - это конечный ресурс, и вы должны нести ответственность при использовании динамического распределения.

Другие вопросы по тегам