Идеи о том, что «проверка на malloc
на отказ бесполезна из-за чрезмерной загрузки» или что «ОС будет уже повреждена к моменту сбоя malloc
», серьезно устарели. Надежные операционные системы никогда не перегружали память, а исторически не такие надежные (как Linux) в настоящее время имеют простые способы отключить чрезмерную загрузку и защитить систему от искажения из-за истощения памяти - , пока приложения выполняют свою роль не грохнуться и не сгореть при сбое malloc
!
Существует множество причин, по которым malloc
может дать сбой в современной системе:
- Недостаточно физических ресурсов для создания экземпляра памяти.
- Виртуальное адресное пространство исчерпано, даже когда имеется много свободной физической памяти. Это может легко произойти на 32-разрядной машине (или 32-разрядном пользовательском пространстве) с> 4 ГБ оперативной памяти + swap.
- Фрагментация памяти. Если ваши схемы распределения очень плохие, вы можете получить 4 миллиона 16-байтовых блоков, разделенных равномерно на 1000 байтов, и неспособных удовлетворить вызов
malloc(1024)
.
Как вы справляетесь с исчерпанием памяти, зависит от характера вашей программы.
Конечно, с точки зрения здоровья системы в целом, хорошо, что ваша программа умерла. Это уменьшает нехватку ресурсов и может позволить другим приложениям продолжать работу. С другой стороны, пользователь будет очень расстроен, если это будет означать потерю часов работы, редактирование видео, ввод бумаги, составление блога, кодирование и т. Д. Или они могут быть счастливы, если их mp3-плеер внезапно умирает из-за -память означает, что их диск перестает работать, и они могут вернуться к своему текстовому процессору и нажать «сохранить».
Что касается исходного вопроса OP, я бы настоятельно рекомендовал не писать malloc
упаковщиков, которые умирают при сбое, или писать код, который просто предполагает, что он будет зависать сразу после использования нулевого указателя, если malloc
не удастся. Это простая дурная привычка, и если вы напишете код, полный непроверенных выделений, то впоследствии невозможно будет повторно использовать этот код в любой программе, где важна надежность.
Гораздо лучшим решением будет просто возвращать ошибку вызывающей функции и позволять вызывающей функции возвращать ошибку своей вызывающей функции и т. Д., Пока вы не вернетесь обратно к main
или подобному, где вы можете написать if (failure) exit(1);
. Таким образом, код можно сразу же повторно использовать в других ситуациях, когда вам может понадобиться проверить ошибки и предпринять какие-то шаги по восстановлению, чтобы освободить память, сохранить / выгрузить ценные данные на диск и т. Д.