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

Linux оптимистичный malloc: будет ли новый всегда бросать, когда не хватает памяти?

Я читал об условиях нехватки памяти в Linux, и следующий параграф из man-страниц заставлял меня думать:

По умолчанию Linux следует оптимистичной стратегии распределения памяти. Это означает, что когда malloc() возвращает не-NULL, нет гарантии, что память действительно доступна. Это очень плохая ошибка. В случае, если окажется, что система не в памяти, один или несколько процессов будут убиты печально известным убийцей OOM. [...]

Учитывая, что новая реализация оператора закончится вызовом malloc в какой-то момент, есть ли какие-либо гарантии того, что новый будет фактически бросать Linux? Если нет, то как вы справляетесь с этой, по-видимому, необнаруживаемой ошибкой?

4b9b3361

Ответ 1

Это зависит; вы можете настроить параметры переназначения ядра, используя vm.overcommit_memory.

Herb Sutter обсудил несколько лет назад, как это поведение фактически несоответствует стандарту С++:

"В некоторых операционных системах, в том числе и в Linux, распределение памяти всегда преуспевает. Полная остановка. Как распределение всегда может быть успешным, даже если запрошенная память действительно недоступна? Причина в том, что само распределение просто записывает запрос на память, под обложками (физическая или виртуальная) память фактически не привязана к процессу запроса, с реальным хранилищем резервных копий, пока фактически не используется память.

" Обратите внимание, что если новый объект напрямую использует объекты операционной системы, то новый всегда будет иметь успех, но любой более поздний невинный код, такой как buf [100] = 'c'; может вызывать или прерываться или останавливаться. С точки зрения стандартного С++, оба эффекта являются несоответствующими, потому что для стандарта С++ требуется, чтобы, если новый не может обеспечить достаточную память, он должен потерпеть неудачу (это не так), и этот код, такой как buf [100] = 'c', не должен генерировать исключение или иначе fail (это может быть).

Ответ 2

Вы не можете справиться с этим в своем программном обеспечении, просто и просто.

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

Но, как вы видите, все это происходит внутри ядра, ваше приложение не может этого видеть. Если это критическая система, вы можете отключить overcommit alltogether в системе.

Ответ 3

Я думаю, что malloc все равно может вернуть NULL. Причина в том, что существует разница между доступной системной памятью (RAM + swap) и количеством в адресном пространстве вашего процесса.

Например, если вы запрашиваете 3 ГБ памяти из malloc на стандартном x86 linux, он обязательно вернет NULL, поскольку это невозможно, учитывая объем памяти, предоставляемый приложениям пользовательского пространства.

Ответ 4

Простите меня, если я ошибаюсь, но не пытаюсь обнулить выделенную память, чтобы гарантировать, что у вас есть каждый байт, который вы запросили? Или даже просто записывая последний байт, он выдавал бы исключение, если бы память не была твоей прав?

Если это правда, вы можете просто попробовать записать последний (и первый?) байт памяти и посмотреть, работает ли он нормально, а если нет, вы можете вернуть null из malloc.

Ответ 5

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