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

При каких обстоятельствах malloc возвращает NULL?

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

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

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

4b9b3361

Ответ 1

Да.

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

malloc(SIZE_MAX)

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

Ответ 2

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

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

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

И снова ваше редактирование:

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

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

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

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

Ответ 3

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

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

 ulimit -v 5000

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

Ответ 4

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

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

Ответ 5

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

char *foo = malloc(0);

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

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

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

Ответ 6

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

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

Ответ 7

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

Ответ 8

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

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

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

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

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

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

Ответ 9

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

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

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