Раздел 9.6 «Overcommit and OOM» в документе, который упоминает @dunxd, особенно наглядно показывает опасность разрешения overcommit. Тем не менее, 80
мне это тоже показалось интересным, поэтому я провел несколько тестов.
Я обнаружил, что это overcommit_ratio
влияет на общую оперативную память, доступную для всех процессов. Корневые процессы, похоже, не обрабатываются иначе, чем обычные пользовательские процессы.
Установка отношения к 100
или меньше должна обеспечить классическую семантику, где возвращаемые значения malloc/sbrk
надежны. Установка коэффициентов ниже, чем это 100
может быть способом зарезервировать больше оперативной памяти для непроцессных операций, таких как кэширование и так далее.
Итак, на моем компьютере с 24 ГБ ОЗУ, с отключенной подкачкой, 9 ГБ в использовании, с top
показом
Mem: 24683652k total, 9207532k used, 15476120k free, 19668k buffers
Swap: 0k total, 0k used, 0k free, 241804k cached
Вот некоторые overcommit_ratio
настройки и объем оперативной памяти, которую могла бы получить моя программа-потребитель (касаясь каждой страницы) - в каждом случае программа выходила чисто после malloc
сбоя.
50 ~680 MiB
60 ~2900 MiB
70 ~5200 MiB
100 ~12000 MiB
Запуск нескольких одновременно, даже с некоторыми из них как пользователем root, не изменил общее количество, которое они потребляли вместе. Интересно, что он не мог потреблять последние 3+ ГиБ или около того; free
не опускалась значительно ниже того , что показано здесь:
Mem: 24683652k total, 20968212k used, 3715440k free, 20828k buffers
Эксперименты были беспорядочными - все, что использует malloc в тот момент, когда используется вся ОЗУ, может привести к сбою, так как многие программисты ужасно относятся к проверке сбоев malloc в C, некоторые популярные библиотеки коллекций игнорируют его полностью, а C ++ и различные другие языки даже хуже.
Большинство ранних реализаций мнимой ОЗУ, которые я видел, предназначались для обработки очень специфического случая, когда один какой-то большой процесс - скажем, 51% + доступной памяти - был необходим fork()
для exec()
какой-то вспомогательной программы, обычно намного, намного меньшего размера. Операционные системы с семантикой копирования при записи позволили бы fork()
, но с условием, что если разветвленный процесс действительно попытается изменить слишком много страниц памяти (каждая из которых затем должна будет создаваться как новая страница, независимая от первоначального огромного процесса) это закончится тем, что его убьют. Родительский процесс был только в опасности, если выделил больше памяти, и мог справиться с исчерпанием, в некоторых случаях, просто подождав немного, пока какой-то другой процесс умрет, а затем продолжил. Дочерний процесс обычно просто заменяет себя (обычно меньшей) программой черезexec()
и был тогда свободен от оговорки.
Концепция чрезмерной fork()
загрузки в Linux - это экстремальный подход, позволяющий как происходить, так и обеспечивать массовое перераспределение отдельных процессов. Случаи смерти, вызванные OOM-убийцами, происходят асинхронно, даже с программами, которые действительно ответственно обрабатывают распределение памяти. Лично я ненавижу общесистемную перегрузку в целом и оком-убийцу в частности - она поощряет дьявольский подход к управлению памятью, который заражает библиотеки и через них каждое приложение, которое их использует.
Я бы предложил установить соотношение равным 100, а также иметь раздел подкачки, который, как правило, в конечном итоге будет использоваться только огромными процессами, которые часто используют лишь небольшую часть той части себя, которая вставляется в своп, и, таким образом, защитить подавляющее большинство процессов от неправильной работы убийцы OOM. Это должно сохранить ваш веб-сервер в безопасности от случайной смерти, и если он был написан для malloc
ответственного обращения , даже в безопасности от самоубийства (но не делайте ставку на последний).
Это означает, что я использую это в /etc/sysctl.d/10-no-overcommit.conf
vm.overcommit_memory = 2
vm.overcommit_ratio = 100