Розділ 9.6 "Overcommit and OOM" в документі, який згадує @dunxd, особливо графічно свідчить про небезпеку дозволення перевиконання комісії. Однак 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+ GiB або близько того; free
не опускалася значно нижче того , що показано тут:
Mem: 24683652k total, 20968212k used, 3715440k free, 20828k buffers
Експерименти були безладними - все, що використовує malloc на даний момент, коли вся оперативна пам'ять використовується, має тенденцію до краху, оскільки багато програмістів страшно перевіряти на предмет відмов malloc в C, деякі популярні бібліотеки колекцій цілком ігнорують його, а C ++ та різні інші мови навіть гірше.
Більшість ранніх впроваджень уявної оперативної пам’яті, яку я бачив, мали справу з дуже конкретним випадком, коли потрібен один великий процес - скажімо 51% + наявної пам’яті - для fork()
того, щоб exec()
якась програма підтримки, як правило, значно, набагато менша. ОС з семантикою копіювання при записі дозволяла б fork()
, але за умови, що якщо роздвоєний процес насправді намагається змінити занадто багато сторінок пам’яті (кожна з яких потім повинна бути створена як нова сторінка, незалежна від початкового величезного процесу) це врешті-решт буде вбито. Батьківський процес загрожував лише тим, що виділивши більше пам’яті, і він міг би впоратися із закінченням, у деяких випадках просто зачекавши трохи, коли якийсь інший процес загине, а потім продовжиться. Дочірній процес зазвичай просто замінюється програмою (як правило, меншою) черезexec()
і тоді він був звільнений від застереження.
Концепція overcommit Linux є надзвичайним підходом до того, щоб дозволити як fork()
відбуватися, так і дозволяти одиночним процесам масово перерозподіляти. Смерть, спричинені вбивцею OOM, трапляються асинхронно, навіть із програмами, які працюють з розподілом пам'яті відповідально. Я особисто ненавиджу загальносистемну подолання загалом і особливо убивцю, - зокрема, це сприяє диявольському підходу до управління пам’яттю, яка заражає бібліотеки, і через них кожен додаток, який їх використовує.
Я б запропонував встановити співвідношення до 100, а також мати розділ swap, який, як правило, лише звикне до величезних процесів - які часто використовують лише крихітну частину самої себе частини, яка набивається в своп, і таким чином захистити переважну більшість процесів від невдач вбивств OOM. Це повинно захищати ваш веб-сервер від випадкової смерті, і якщо це було написано, щоб поводитися malloc
відповідально, навіть захистити себе від вбивства (але не ставте ставку на останнє).
Це означає, що я використовую це в /etc/sysctl.d/10-no-overcommit.conf
vm.overcommit_memory = 2
vm.overcommit_ratio = 100