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

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

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

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

Ответы [ 5 ]

18 голосов
/ 01 ноября 2009

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

Херб Саттер несколько лет назад обсуждал, как это поведение на самом деле не соответствует стандарту C ++ :

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

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

9 голосов
/ 01 ноября 2009

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

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

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

4 голосов
/ 01 ноября 2009

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

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

3 голосов
/ 01 ноября 2009

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

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

1 голос
/ 01 ноября 2009

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

...