Могу ли я полагаться на malloc, возвращающий NULL?

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

В соответствующей заметке Херб Саттер говорит, что обработка ошибок памяти C ++ бесполезна, потому что система будет входить в спазмы пейджинга задолго до того, как на самом деле произойдет исключение. Это относится также к malloc ?

Цитирование руководств Linux :

По умолчанию Linux следует оптимистичной страtagsи распределения памяти. Это означает, что когда malloc() возвращает не NULL нет гарантии, что память действительно доступна. Это очень плохая ошибка. В случае, если окажется, что система не в памяти, один или несколько процессов будут убиты печально известным убийцей OOM. В случае использования Linux в ситуациях, когда было бы менее желательно внезапно потерять некоторые случайно выбранные процессы, и, кроме того, версия ядра достаточно современна, можно отключить это чрезмерное поведение, используя команду:

 # echo 2 > /proc/sys/vm/overcommit_memory 

Вы должны проверить возврат NULL , особенно на 32-битных системах, поскольку адресное пространство процесса может быть исчерпано задолго до ОЗУ: например, на 32-битной Linux пользовательские процессы могут иметь полезное адресное пространство 2G-3G, в отличие от более 4 ГБ общей оперативной памяти. В 64-битных системах было бы бесполезно проверять код возврата malloc , но в любом случае можно считать хорошей практикой, и это сделает вашу программу более переносимой. И, помните, разыменование нулевого указателя убивает ваш процесс, конечно; некоторые подкачки могут не сильно повредить по сравнению с этим.

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

Оператор C ++ по умолчанию, используемый по умолчанию, часто является оберткой над теми же механизмами распределения, которые используются malloc() .

В Linux вы действительно не можете полагаться на malloc возвращающий NULL если достаточная память недоступна из-за страtagsи общего назначения ядра, но вы все равно должны ее проверить, потому что в некоторых случаях malloc вернет NULL , например, когда вы запрашиваете больше памяти, чем доступных в машине в целом. Справочная система Linux malloc(3) называет обход «действительно плохой ошибкой» и содержит рекомендации о том, как отключить ее.

Я никогда не слышал об этом поведении, которое также встречается в других вариантах Unix.

Что касается «спазмов пейджинга», это зависит от настройки машины. Например, я предпочитаю не устанавливать раздел подкачки на ноутбуках Linux, так как точное поведение, которое вы опасаетесь, может убить жесткий диск. Мне все равно понравятся программы C / C ++, которые я запускаю, чтобы проверить возвращаемые значения malloc , дать соответствующие сообщения об ошибках и, по возможности, очистить их после себя.

Проверка возврата malloc не поможет вам самостоятельно сделать ваши распределения более безопасными или менее подверженными ошибкам. Это может быть даже ловушка, если это единственный тест, который вы реализуете.

При вызове с аргументом 0 стандарт позволяет malloc возвращать уникальный адрес, который не является нулевым указателем и который у вас пока не имеет права доступа. Поэтому, если вы просто проверяете, является ли возврат 0 но не проверяют аргументы в malloc , calloc или realloc вы можете столкнуться с segfault намного позже.

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

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

Я думаю, что эта «проверка возвращения malloc » сильно завышена, иногда даже защищена довольно догматично. Другие вещи гораздо важнее:

  • всегда всегда инициализируйте переменные. для переменных указателя это имеет решающее значение, пусть программа сработает хорошо, прежде чем все станет слишком плохо. Неинициализированные члены указателя в struct s являются важной причиной ошибок, которые трудно найти.
  • всегда проверяйте аргумент malloc и Co., если это постоянная времени компиляции, такая как sizof toto не может быть проблемой, но всегда убедитесь, что ваше векторное распределение правильно обрабатывает нулевой регистр.

Легкой проверкой на возврат malloc является его завершение чем-то вроде memset(malloc(n), 0, 1) . Это просто записывает 0 в первый байт и красиво падает, если malloc имел ошибку, или n начиналось с 0.

Чтобы просмотреть это с другой точки зрения:

mallocmalloc может возвращать указатель не-NULL, даже если память фактически недоступна”, не означает, что он всегда возвращает не-NULL. Там могут (и будут) случаи, когда NULL возвращается (как уже говорили другие), поэтому эта проверка необходима все же.

  • База данных SQLite Android Database Cursor с 2048 КБ не выполнена
  • Как написать безопасный для паролей class?
  • Что такое «кеширующий» код?
  • Адрес указателя в многомерном массиве C
  • Хранилище типов данных типа C ++
  • Каков правильный способ освободить память в C #
  • Средство профилирования .NET Memory
  • Что быстрее: распределение стека или выделение кучи
  • Каков размер стека по умолчанию, может ли он расти, как он работает с сборкой мусора?
  • Как получить размер объекта JavaScript?
  • Linux Allocator не выпускает небольшие куски памяти
  • Давайте будем гением компьютера.