Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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

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

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

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

Ответ 4

Чтобы просмотреть это с альтернативной точки зрения:

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