При каких обстоятельствах Мэллок может вернуть NULL?



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



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



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

571   9  

9 ответов:

Да.

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

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

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

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

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

И повторно отредактируйте:

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

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

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

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

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

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

 ulimit -v 5000

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

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

char *foo = malloc(0);

Цитирование из стандарта C99, §7.20.3, подраздел 1:

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

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

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

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

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

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

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

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

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();, но если вы действительно хотите играть в гольф, вы будете на коде Golf SE.

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

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

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

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

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

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

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

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

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

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

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

Comments

    Ничего не найдено.