При каких обстоятельствах malloc может вернуть NULL? - PullRequest
27 голосов
/ 01 февраля 2012

Со мной такого никогда не было, и я программирую уже много лет.

Может кто-нибудь привести пример нетривиальной программы, в которой malloc на самом деле не будет работать?

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

Ответы [ 9 ]

23 голосов
/ 01 февраля 2012

Вам нужно поработать во встроенных системах, вам часто возвращают NULL: -)

Намного сложнее израсходовать память в современных системах хранения больших массивов адресов и резервных копий, но все еще вполне возможно в приложениях, где вы обрабатываете большие объемы данных, таких как ГИС или базы данных в памяти, или в места, где ваш ошибочный код приводит к утечке памяти.

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

И вы можете отредактировать:

Я не говорю об исчерпании памяти, ...

Само определение исчерпания памяти malloc не дает вам желаемого пространства. Не имеет значения, вызвано ли это выделением всей доступной памяти или фрагментацией кучи, что означает, что вы не можете получить непрерывный блок, даже если совокупность всех свободных блоков на арене памяти выше, или искусственно ограничивает использование адресного пространства, например, с помощью функции, соответствующей стандартам :

void *malloc (size_t sz) { return NULL; }

Стандарт C не различает режимы сбоев, только то, что он успешен или неудачен.

17 голосов
/ 01 февраля 2012

Да.

Просто попробуйте malloc больше памяти, чем может предоставить ваша система (либо исчерпав свое адресное пространство, либо виртуальную память - в зависимости от того, что меньше).

malloc(SIZE_MAX)

, вероятно, сделает это. Если нет, повторите несколько раз, пока не закончится.

9 голосов
/ 01 февраля 2012

Любая программа, написанная на языке c, которая должна динамически выделять больше памяти, чем позволяет текущая ОС.

Для развлечения, если вы используете тип ubuntu в

 ulimit -v 5000

Любая программаваш запуск, скорее всего, приведет к сбою (из-за сбоя malloc), поскольку вы ограничили объем доступной памяти для какого-либо одного процесса значительным количеством.

8 голосов
/ 02 февраля 2012

Если ваша память уже полностью не зарезервирована (или сильно фрагментирована), единственный способ заставить malloc() возвращать NULL -пункт - это запрос пространства нулевого размера:

char *foo = malloc(0);

Ссылаясь на стандарт C99, §7.20.3, подраздел 1:

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

Другими словами, malloc(0) может возвращать NULL -точку или действительный указатель на ноль выделенных байтов.

4 голосов
/ 02 февраля 2012

В более или менее стандартной системе, использующей стандартный однопараметрический malloc, существует три возможных режима отказа (я могу придумать):

1) Запрошенный размер выделения непозволил.Например, некоторые системы могут не разрешать выделение> 16M, даже если доступно больше памяти.

2) Непрерывная свободная область запрошенного размера с границей по умолчанию не может быть расположена в куче.Может все еще быть много кучи, но просто недостаточно в одной части.

3) Общая выделенная куча превысила некоторый «искусственный» предел.Например, пользователю может быть запрещено выделять более 100 миллионов, даже если есть 200 миллионов свободных и доступных «системе» в одной объединенной куче.

(Конечно, вы можете получить комбинации 2 и 3,поскольку некоторые системы выделяют несмежные блоки адресного пространства для кучи по мере ее роста, устанавливая «ограничение размера кучи» на общее количество блоков.)

Обратите внимание, что некоторые среды поддерживают дополнительные параметры malloc, такие как выравниваниеи идентификатор пула, который может добавлять свои собственные повороты.

4 голосов
/ 01 февраля 2012

Просто проверьте страницу справочника по malloc.

В случае успеха указатель на блок памяти, выделенный функцией.
Тип этого указателя всегда void *, чтоможет быть приведен к нужному типу указателя данных для разыменования.
Если функции не удалось выделить запрошенный блок памяти, возвращается нулевой указатель.

3 голосов
/ 01 февраля 2012

Поскольку вы запросили пример, вот программа, которая (в конце концов) увидит malloc возврат NULL:

perror();void*malloc();main(){for(;;)if(!malloc(999)){perror(0);return 0;}}

Что? Вам не нравится намеренно запутанный код? ;) (Если он работает в течение нескольких минут и не падает на вашем компьютере, убейте его, измените 999 на большее число и попробуйте снова.)

РЕДАКТИРОВАТЬ: Если это не работает, независимо от того, насколько большое число, то происходит то, что ваша система говорит "Вот немного памяти!" но пока вы не пытаетесь его использовать, он не выделяется. В каком случае:

perror();char*p;void*malloc();main(){for(;;){p=malloc(999);if(p)*p=0;else{perror(0);return 0;}}

Должен сделать свое дело. Если мы сможем использовать расширения GCC, я думаю, что мы сможем сделать его еще меньше, изменив char*p;void*malloc(); на void*p,*malloc();, но если вы действительно хотите играть в гольф, вы будете на Code Golf SE.

3 голосов
/ 01 февраля 2012

Выберите любую платформу, хотя встроенная, вероятно, проще.malloc (или new) тонна ОЗУ (или утечка ОЗУ со временем, или даже ее фрагментация с использованием наивных алгоритмов).Boom.malloc возвращает мне NULL в случае, когда происходят "плохие" вещи.

В ответ на ваши изменения.Да еще раз.Фрагментация памяти со временем может привести к сбою даже одного выделения int.Также имейте в виду, что malloc не просто выделяет 4 байта для int, но может занимать столько места, сколько ему нужно.Он имеет свой собственный бухгалтерский материал и довольно часто занимает минимум 32-64 байта.

1 голос
/ 01 февраля 2012

Да. Malloc вернет NULL, когда ядро ​​/ системная библиотека будут уверены, что память не может быть выделена.

Причина, по которой вы обычно не видите этого на современных машинах, заключается в том, что Malloc на самом деле не выделяет память, а скорее запрашивает некоторое «виртуальное адресное пространство», зарезервированное для вашей программы, чтобы вы могли писать в нем. Ядра, такие как современный Linux, на самом деле превышают коммит, то есть они позволяют вам выделять больше памяти, чем ваша система может предоставить (подкачка + оперативная память), пока все это вписывается в адресное пространство системы (обычно 48 бит на 64-битных платформах, IIRC) , Таким образом, в этих системах вы, вероятно, вызовете OOM killer, прежде чем вы вызовете возврат NULL-указателя. Хорошим примером является 512 МБ ОЗУ на 32-битной машине: написать программу на C, которая будет съедена убийцей OOM, тривиально из-за того, что она пытается распределить всю доступную RAM + swap.

(Перегрузка может быть отключена во время компиляции в Linux, поэтому это зависит от параметров сборки, будет ли данное ядро ​​Linux перегружено. Однако стандартные дистрибутивные ядра настольных ПК делают это.)

...