Нужно ли чистить память перед exit
Завершает вызывающий процесс. Функция exit завершает его после очистки; _exit и _Exit завершают его мгновенно.
не используйте этот метод для завершения работы приложения универсальная платформа Windows (UWP), за исключением сценариев тестирования или отладки. в соответствии с политиками Microsoft Storeне разрешено закрывать приложения магазина программным способом или с помощью пользовательского интерфейса. Дополнительные сведения см. в статье жизненный цикл приложения UWP. дополнительные сведения о приложениях UWP см. в документации по универсальная платформа Windows.
Синтаксис
5 Answers 5
This is actually a really hard, imponderable question.
Pro (in favor of freeing everything before exit):
- no bugs or memory leaks later if code is rearranged
- no false positives from valgrind or memory leak checker
- no memory leaks if you're running under a buggy OS, or no OS at all
Con (just exit, don't worry about freeing everything):
- freeing everything can be a lot of work
- freeing everything can introduce bugs and crashes
- your OS really, really ought to reclaim all resources for you when you exit
And, one more point (not sure if it's a pro or a con): on the majority of systems, calling free does not return memory to the Operating System (only exiting does that).
In the end, you will have to decide which of these pros and cons matters most for you. Different programmers on different projects under different circumstances will reach different conclusions; there is no one-size-fits-all answer here.
Well said! Restating a comment I made below: if you're a newbie, in general, make "free it manually" the habitual instinct (less dangerous habit), and make "leave it to the OS" be a conscious, informed, case-by-case decision. The decision-making process for that will become instinct over time. Otherwise, you'll habitually forget to free your mallocs and clean up your dangling pointers, and you're subsequently signing up for surprise UBs the next time you change your code in such a way that failing to free the memory now matters.
@JasonMc92 while that sounds nice, it is building extra unreliablity into today's code. Explicitly freeing memory at app termination is not free, not safe and not always possible. It's usually unnecessary extra code that needs to be tested and debugged, over, and over again, on all OS versions. It's uni cargo-cult mantras like 'you must always explicitly free before terminating' that result in the many apps we have both used that will not shut down cleanly and quickly:(
As I said on the other (longer) comment chain: the link in the answer backs up my point. By and large, freeing manually (overall, not just at program end) is usually an issue of stability (short- and long-term), while not freeing manually is usually an issue of performance, and we all know the adage: "Premature optimization is the root of all evil." (-Donald Knuth). Free by habit, decide not to by choice, not to ensure OS gets the memory back, but to prevent errors when we refactor code later. Beyond that, we have a "holy war" and had probably best agree to disagree.
I found running under no OS being the ultimate no memory leaks. When your exit chainloads the next program it comes up just as yours did and sees all the memory in the computer as randomly initialized free memory.
You should always free allocated memory before you exit. As already mentioned in other answers, this will minimize warnings from static- or dynamic analysis tools etc.
But the real reason why you should always do this, is because freeing often exposes dormant run-time bugs in your application.
If you have a bug somewhere that causes memory corruption or changes pointer addresses, that bug may stay silent and dormant. Until you change something completely unrelated to the bug and thereby shuffle around the memory layout. Then suddenly you get a crash and you'll have no idea why, because the bug isn't even located in the code you just added.
By freeing the memory, you provoke such bugs to surface. Because if there is anything wrong with the heap or with the pointers pointing at the heap, then you will often get a crash at the point where you call free() . Which means that you have a severe bug somewhere, that you need to find before shipping the program.
Почему необходимо избегать утечек памяти в процессе работы программы понятно. Но зачем нужно освобождать память динамически объявленных переменных перед завершением работы программы?
Единственный ответ, до которого мы с коллегами пришли: чтобы "зомби" (в Linux), если он появится после завершения программы, занимал минимальное место.
В остальных случаях ОС сама подотрет все, что было занято, разве нет?
Какие еще негативные последствия могут возникнуть?
Смотрите. Никаких причин освобождения памяти перед завершением программы, кроме чисто эстетических, нет. Память всё равно вернётся системе после смерти процесса.
Однако, довольно часто объекты в своём деструкторе совершают дополнительные действия. Закрывают транзакцию в базе данных, корректно закрывают онлайн-сессию, сбрасывают изменённые данные на диск и т. п. Таким образом, если такой объект «утечёт», то программа после завершения оставит что-то в некорректном состоянии.
Если ваша программа маленькая, вы можете её полностью обозреть, и вы уверены, что кроме утечек памяти ничего плохого от пропущенных деструкторов не случится — можете смело оставлять в конце память.
Но если ваш проект большой, то скорее всего у вас не будет полного обзора того, что какой модуль делает. В такой ситуации лучше придерживаться дисциплинированного подхода и чистить за собой.
Добавлю свои пять копеек. Это может помочь при поиске других ошибок: вывод valgrind куда проще и понятнее, когда устранены "необязательные" ошибки с неосвобожденной памятью, коих можно было избежать.
Перед завершением работы программы нужно убедиться, что разделяемые ресурсы освобождены, например, соединения с базой данных и веб-серверами закрыты. Серверы какое-то время могут считать ваш клиент всё ещё подключенным, что нежелательно. Следует сбросить данные на диск в файлах, если вам есть дело до их содержимого. Если вам всё равно, то можно не закрывать — система справится сама.
Освобождать память обычно ненужно, хоть это и является правилом хорошего тона. Более того, если ваша программа выделила очень много сложных объектов в памяти, и память частично свалилась в своп, то может быть выгодно не освобождать память, чтобы не заставлять систему вытаскивать информацию с диска только для того, чтобы её выбросить.
Если вы хотите быстро завершить процесс, то можете аккуратно разрушить объекты, которые хранят ссылки на разделяемые ресурсы, а потом просто убить процесс.
Более того, в идеале программа должна корректно обрабатывать случай убийства процесса в любой момент. Данные при этом не должны быть повреждены. Отработка случая жёсткого убийства процесса без аккуратного освобождения памяти и ресурсов — это важный момент при разработке программ. Из-за этого ваша программа не должна перестать быть работоспособной (например, из-за повреждения конфигурационных файлов).
Есть похожие вопросы повсюду, и один из них закрыт с этого сайта обмена стеками. Но даже несмотря на то, что я многому научился, читая их, ни один из них не дает точного ответа на мой вопрос.
Вот вопрос, допустим, у меня есть эта программа (это очень упрощенная версия)
В этой программе, parent process делает свое дело на некоторое время, выделяет много процесса в heap , free некоторые, держать другие на потом и в какой - то момент он хочет выполнить какую - либо команду, но он не хочет прекратить, так что создает child делать ее прикус.
Ребенок затем вызывает другую функцию , которая будет делать какую - то задачу , и в конечном использовании execve в execute команду , переданной ей. Если это было успешно, не было бы никаких проблем, так как исполняемая программа будет обрабатывать все выделенные пространства, но если это не удалось, дочерний элемент выходит с кодом состояния. Родитель ждет ответа ребенка, и когда он это делает, он переходит к своей следующей процедуре. Проблема здесь в том, что, когда child не удается выполнить, все данные кучи остаются выделенными, но имеет ли это значение? поскольку,
- он собирается выйти в следующей строке,
- Несмотря на то, что я начинаю с этого, я узнал, что новый process создается во время fork , поэтому утечка памяти не должна влиять на, parent поскольку он вот- child вот умрет.
- Если мое предположение верно и эти утечки на самом деле не имеют значения, почему valgrind о них сетуют?
- Есть ли лучший способ free сохранить все воспоминания в дочерней куче, не передавая все воспоминания ( str, и другие в этом примере) в функцию execute и free каждый раз вызывая их кропотливо ? действительно kill() есть механизм для этого?
Редактировать
Вот рабочий код
Когда внутри дочернего процесса есть свободное пространство, это результат valgrinds.
Как видите, общей ошибки ( ) нет, поскольку эта программа недолговечна. Но в моей реальной программе с бесконечным циклом каждая проблема в child ( ) имеет значение. Поэтому я спрашивал, беспокоит ли меня эта утечка воспоминаний в этом дочернем процессе непосредственно перед выходом и выследить их или просто оставить их такими, как они находятся в другом виртуальном пространстве, и они очищаются при выходе из их процессов (но в этом случае почему valgrind все еще жалуются на них, если их соответствующий процесс очищает их во время выхода)
Должен ли я освобождать всю мою распределенную память, когда я выхожу из программы из-за ошибки?
Хотя это правда, что ОС сделает это за вас, что произойдет, когда OP добавит новую функцию для выполнения некоторой обработки, а затем еще одну, а затем еще одну? Или, что еще хуже, когда приходит новый парень (девушка) и начинает видоизменяться? Мой совет: освободите всю выделенную память. Да, и не забрасывайте результаты ваших выделений. Всегда.
Одно из преимуществ отказа от освобождения состоит в том, что если ваша программа имеет большое количество распределений, то освобождение при выходе замедлит последовательность выхода вашего приложения.
На самом деле это действительно сложный и непонятный вопрос.
Pro (за то, чтобы освободить все перед выходом):
- никаких ошибок или утечек памяти позже, если код будет изменен
- нет ложных срабатываний от valgrind или средства проверки утечки памяти
- нет утечек памяти, если вы работаете под глючной ОС или вообще без ОС
Против (просто выйдите, не беспокойтесь об освобождении всего):
- освободить все может быть много работы
- освобождение всего может привести к ошибкам и сбоям
- ваша ОС действительно должна освободить для вас все ресурсы, когда вы выйдете
И еще один момент (не уверен , если это про или кон): на большинстве систем, называя free это не возвращают память к операционной системе (только выход делает это).
В конце концов, вам придется решить, какие из этих плюсов и минусов для вас наиболее важны. Разные программисты, работающие над разными проектами при разных обстоятельствах, придут к разным выводам; здесь нет универсального ответа.
Хорошо сказано! Повторяю комментарий, который я сделал ниже: если вы новичок, в общем, сделайте «освободить вручную» привычным инстинктом (менее опасная привычка) и сделайте «оставьте это ОС» осознанным, информированным, индивидуальным Случайное решение. Со временем процесс принятия решения станет инстинктивным. В противном случае вы обычно забываете освобождать свои маллоки и очищать свисающие указатели, и впоследствии вы подписываетесь на неожиданные UB в следующий раз, когда вы изменяете свой код таким образом, что неспособность освободить память теперь имеет значение .
@ JasonMc92, хотя это звучит неплохо, но сегодня код делает его ненадежным. Явное освобождение памяти при завершении работы приложения не является бесплатным, небезопасным и не всегда возможным. Обычно это ненужный дополнительный код, который необходимо снова и снова тестировать и отлаживать во всех версиях ОС. Это мантры uni cargo-cult, такие как «вы всегда должны явно освободить перед завершением», что приводит к тому, что многие приложения, которые мы оба использовали, не закрываются чисто и быстро :(
Как я уже сказал о другой (более длинной) цепочке комментариев: ссылка в ответе подтверждает мою точку зрения. По большому счету , освобождение вручную (в целом, а не только в конце программы) обычно является проблемой стабильности (краткосрочной и долгосрочной), в то время как невыполнение вручную обычно является проблемой производительности, и все мы знаем пословицу: «Преждевременное оптимизация - корень всех зол ". (-Дональд Кнут). Свободен по привычке, решите не делать этого по собственному желанию, не для того, чтобы ОС вернула память, а для предотвращения ошибок при последующем рефакторинге кода. Кроме того, у нас есть «священная война», и, вероятно, лучше всего согласиться с тем, чтобы не соглашаться.
Я обнаружил, что работа без ОС означает отсутствие утечек памяти. Когда ваша программа выхода загружает следующую программу, она появляется так же, как и ваша, и видит всю память в компьютере как произвольно инициализированную свободную память.
Вы можете возразить, что если для освобождения требуется много работы, значит, программа плохо спроектирована.
Перед выходом всегда следует освобождать выделенную память. Как уже упоминалось в других ответах, это минимизирует предупреждения от инструментов статического или динамического анализа и т. Д.
Но настоящая причина, по которой вы всегда должны это делать, заключается в том, что при освобождении часто обнаруживаются неактивные ошибки времени выполнения в вашем приложении.
Если у вас где-то есть ошибка, которая вызывает повреждение памяти или изменяет адреса указателей, эта ошибка может оставаться незамеченной и неактивной. Пока вы не измените что-то совершенно не связанное с ошибкой и, таким образом, не измените структуру памяти. Затем внезапно вы получаете сбой, и вы не понимаете, почему, потому что ошибка даже не находится в только что добавленном коде.
Освобождая память, вы заставляете всплывать на поверхность такие ошибки. Потому что, если что-то не так с кучей или с указателями, указывающими на кучу, вы часто получаете сбой в точке, где вы вызываете free() . Это означает, что у вас где-то есть серьезная ошибка, которую вам нужно найти перед отправкой программы.
Этот ответ хорош, потому что он выходит за рамки идеи простого обсуждения части «священной войны» в этой теме. Спасибо @Lundin, ценные очки!
Это зависит от ОС. Лучшая практика Я бы сказал, вы должны явно освободить его. Он также позволяет использовать такие инструменты, как valgrind a PITA, если у вас есть память, которая не освобождена повсюду, и я не могу сказать, что хорошо, а что плохо и т. Д.
Если в ОС, которая явно освобождает память, у вас все еще есть проблема с другими ресурсами. Когда ваше приложение начнет расти и привлекать сторонние библиотеки, вы можете получить утечки ресурсов. Представьте, что я написал библиотеку, которая просит вас вызвать close для обработчика. Этот обработчик поддерживается временными файлами, которые не удаляются, пока вы не вызовете close. Или я отключил процессы, работающие в фоновом режиме, которыми я управляю с помощью сигналов или какого-либо другого ресурса, о котором вы не знаете.
Способ обработки временных файлов - их удаление при запуске, а не при завершении работы. Электропитание может выйти из строя в любой момент, и приложения, которые полностью полагаются на процедуру выключения, столкнутся с проблемами.
@Harry Если вы программируете для такой системы, вы это знаете и не задавайте такого рода вопросы о переполнении стека.
Параметры
status
Код состояния завершения.
Комментарии
Функции exit , _Exit и _exit завершают вызывающий процесс. exit Функция вызывает деструкторы для локальных объектов потока, а затем вызывает — их в порядке ЛИФО, — atexit _onexit а затем сбрасывает все буферы файлов до того, как он завершит процесс, а затем записывает их в очередь. Функции _Exit и _exit завершают процесс без удаления объектов локального потока или обработки функций atexit или _onexit , а также без очистки буферов потока.
Хотя exit _Exit _exit вызовы и не возвращают значение, значение в status становится доступным для среды размещения или ожидающего вызова процесса, если он существует, после завершения процесса. Как правило, вызывающая функция задает для status значение 0 для указания нормального завершения или принимает другое значение для указания ошибки. Значение status становится доступным для пакетной команды операционной системы ERRORLEVEL и представлено одной из двух констант: EXIT_SUCCESS , которая представляет значение 0, или EXIT_FAILURE , которая представляет значение 1.
Функции exit , _Exit , _exit , quick_exit , _cexit и _c_exit ведут себя следующим образом.
Функция | Описание |
---|---|
exit | Выполняет полные процедуры завершения библиотеки C, завершает процесс и предоставляет полученный код состояния среде узла. |
_Exit | Выполняет минимальные процедуры завершения библиотеки C, завершает процесс и предоставляет полученный код состояния среде узла. |
_exit | Выполняет минимальные процедуры завершения библиотеки C, завершает процесс и предоставляет полученный код состояния среде узла. |
quick_exit | Выполняет быстрые процедуры завершения библиотеки C, завершает процесс и предоставляет полученный код состояния среде узла. |
_cexit | Выполняет полные процедуры завершения библиотеки C и возвращает управление вызывающему объекту. Не завершает процесс. |
_c_exit | Выполняет минимальные процедуры завершения библиотеки C и возвращает управление вызывающему объекту. Не завершает процесс. |
При вызове exit функции, _Exit или _exit , деструкторы для любых временных или автоматических объектов, существующих во время вызова, не вызываются. Автоматический объект — это не статический локальный объект, определенный в функции. Временный объект — это объект, созданный компилятором, например значение, возвращаемое вызовом функции. Чтобы уничтожить автоматический объект перед вызовом exit , _Exit или _exit , явно вызовите деструктор для объекта, как показано ниже:
Не используйте DLL_PROCESS_ATTACH для вызова exit из DllMain . Чтобы выйти DLLMain из функции, вернитесь FALSE из DLL_PROCESS_ATTACH .
По умолчанию глобальное состояние этой функции ограничивается приложением. Чтобы изменить это, см. раздел глобальное состояние в CRT.
Should I free all my mallocated memory when I am exiting program in the due of error?
While it is true that the OS will do it for you, what happens when OP adds a new function to do some processing and then another and then another? Or worse, when the new guy (gal) comes on and starts modifying? My advice, free all allocated memory. Oh, and do not cast the results of your allocations. Ever.
One advantage of not freeing is that if your program has a large number of allocations, then freeing on exit will slow down your application's exit sequence.
Читайте также: