Могу ли я рассчитывать на то, что malloc вернет NULL? - PullRequest
17 голосов
/ 31 октября 2011

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

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

Ответы [ 4 ]

32 голосов
/ 31 октября 2011

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

По умолчанию Linux использует оптимистичную стратегию выделения памяти.Это означает, что когда malloc() возвращает не-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().

5 голосов
/ 31 октября 2011

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

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

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

2 голосов
/ 31 октября 2011

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

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

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

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

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

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

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

1 голос
/ 31 октября 2011

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...