
Относится к вопросу SuperUser наhttps://superuser.com/questions/200387/linux-overcommit-memoryМой вопрос: по какой причине они разрешили перерасход по умолчанию?
Начиная с версии 2.5.30 значения следующие: 0 (по умолчанию): как и прежде: предположение о том, какой объем избыточных обязательств является разумным,
решение1
Значительная часть необходимости в избыточном выделении памяти в Linux (и в системах Unix в целом) обусловлена необходимостью реализации fork()
системного вызова, который дублирует адресное пространство вызывающего процесса.
Чаще всего за этим системным вызовом следует exec()
, комбинация которых приводит к созданию отдельной программы как дочернего процесса текущего процесса, в этом случае большая часть дублированного адресного пространства в конечном итоге не будет использоваться.
Чтобы сделать это эффективно, Linux использует копирование при записи, чтобы избежать дублирования памяти вызывающего приложения fork()
, в этом случае ему не придется копировать все страницы, а просто отбросить их вскоре после exec()
вызова.
Но в момент fork()
вызова нет способа сказать, exec()
придет ли . Вполне возможно, что это используется для порождения рабочих потомков и что повторное использование адресного пространства родителя является желаемым. (Эта техника была довольно популярна в демонах, использующих предварительно разветвленные рабочие для обработки соединений.) В этом случае большинство или, по крайней мере, некоторые требования к памяти будут существовать для разветвленного потомка (возможно, не 100% памяти родителя, но можно предположить, что большая ее часть.)
Но постоянное резервирование памяти для этого случая проблематично для случая fork()
+ exec()
, особенно если родительский процесс является долго выполняющимся, который резервирует несколько гигабайт памяти и разветвляет много потомков. Если бы не overcommit, вам пришлось бы резервировать сумму, в общей сложности равную многим гигабайтам, используемым родителем, и это для каждого разветвленного потомка. Но ничего (или почти ничего) из этого не будет реально использовано, так как exec()
это резервирование будет немедленно сброшено. Конечный результат заключается в том, что такая рабочая нагрузка потребует либо огромного количества пространства подкачки (чтобы справиться с резервированием, большая его часть будет неиспользованной, но должна быть там в худшем случае), либо чего-то вроде overcommit.
Хотя fork()
это отличная иллюстрация этого примера, другие API в Linux/Unix также приводят к необходимости перерасхода. Например, когда malloc()
вызывается (или, точнее, системные вызовы, реализующие его), память фактически не выделяется, пока ее не «тронет» процесс, поэтому совершенно допустимо выделить очень большой блок гигабайт и использовать его скудно, так что фактически будет использовано только несколько мегабайт. Тот факт, что эти API работают таким образом, означает, что программы используют эти свойства, то есть они, скорее всего, сломаются при отсутствии перерасхода (если только у вас действительно нет большого объема памяти или подкачки, которую можно потратить впустую, поддерживая эти резервирования.)
Интересное обсуждение этого вопроса fork()
можно найти наэтот пост LWN о статье из Microsoft Research. Статья сама по себе интересная, конечно. Но вы видите, как комментарии сразу переходят к overcommit и проблемам с ним.
Статья называетсяРазвилка на дороге.
решение2
Я думаю, причина в том, что не у всех людей достаточно ресурсов для покупки памяти, поэтому в таких случаях все приложения должны работать правильно, поэтому полезно запускать приложения с низкими ресурсами.