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

17

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

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

    
задан fredoverflow 30.10.2011 в 22:13
источник

4 ответа

32

Цитирование руководств 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 тоже может выйти из строя, пока не будет достаточно доступна память.

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

    
ответ дан Antti Haapala 30.10.2011 в 22:17
источник
5

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

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

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

    
ответ дан Fred Foo 30.10.2011 в 22:18
источник
2

Проверка возврата 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 для начала.

    
ответ дан Jens Gustedt 30.10.2011 в 23:32
источник
1

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

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

    
ответ дан glglgl 30.10.2011 в 22:27
источник