Řešení 1:
Nastavení overcommit_ratio
na 80 pravděpodobně není správná akce. Nastavení hodnoty na cokoliv menšího než 100 je téměř vždy nesprávné.
Důvodem je to, že linuxové aplikace alokují více, než skutečně potřebují. Řekněme, že alokují 8 kb pro uložení několika znakového řetězce textu. To je několik KB nevyužitých. Aplikace to dělají hodně a k tomu je určen overcommit.
Takže v podstatě s overcommitem na 100 jádro nedovolí aplikacím alokovat více paměti, než máte (swap + ram). Nastavení na méně než 100 znamená, že nikdy nevyužijete celou svou paměť. Pokud se chystáte nastavit toto nastavení, měli byste ho nastavit na vyšší hodnotu než 100 kvůli výše zmíněnému scénáři, což je docela běžné.
Nyní, pokud jde o váš problém se spouštěním OOM zabijáka, ruční nastavení overcommit to pravděpodobně nevyřeší. Výchozí nastavení (heuristické určení) je poměrně inteligentní.
Chcete-li zjistit, zda je toto skutečně příčinou problému, podívejte se na /proc/meminfo
když OOM zabiják běží. Pokud vidíte, že Committed_AS
se blíží CommitLimit
, ale free
stále zobrazuje dostupnou volnou paměť, pak ano, můžete ručně upravit překročení pro váš scénář. Nastavení této hodnoty příliš nízko způsobí, že OOM zabiják začne zabíjet aplikace, když máte stále dostatek volné paměti. Nastavení příliš vysoké může způsobit, že náhodné aplikace zemřou, když se pokusí využít paměť, která jim byla přidělena, ale ve skutečnosti není dostupná (když se všechna paměť skutečně spotřebuje).
Řešení 2:
Oddíl 9.6 „Overcommit and OOM“ v dokumentu, který @dunxd zmiňuje, je obzvláště názorný na nebezpečí povolení overcommit. Nicméně malloc/sbrk
také mi to připadalo zajímavé, tak jsem provedl několik testů.
Zjistil jsem, že overcommit_ratio
ovlivňuje celkovou RAM dostupnou pro VŠECHNY procesy. Zdá se, že s kořenovými procesy se nezachází jinak než s běžnými uživatelskými procesy.
Nastavení poměru na 100
nebo méně by měly poskytovat klasickou sémantiku, kde vrací hodnoty z malloc/sbrk
jsou spolehlivé. Nastavení poměrů nižší než 100
může být způsob, jak vyhradit více paměti RAM pro neprocesní činnosti, jako je ukládání do mezipaměti a tak dále.
Takže na mém počítači s 24 GiB RAM, se zakázaným swapem, 9 GiB v použití, s top
zobrazení
Mem: 24683652k total, 9207532k used, 15476120k free, 19668k buffers
Swap: 0k total, 0k used, 0k free, 241804k cached
Zde jsou některé overcommit_ratio
nastavení a kolik RAM mohl můj spotřebitelský program ram uchopit (dotykem na každou stránku) - v každém případě se program ukončil čistě jednou malloc
selhalo.
50 ~680 MiB
60 ~2900 MiB
70 ~5200 MiB
100 ~12000 MiB
Spuštění několika najednou, dokonce i s některými jako uživatel root, nezměnilo celkové množství, které společně spotřebovali. Je zajímavé, že nebyl schopen spotřebovat posledních 3+ GiB nebo tak; free
nekleslo moc pod to, co je zde zobrazeno:
Mem: 24683652k total, 20968212k used, 3715440k free, 20828k buffers
Experimenty byly chaotické – vše, co v tuto chvíli používá malloc, má tendenci se zhroutit, protože mnoho programátorů je hrozných při kontrole chyb malloc v C, některé oblíbené knihovny sbírek to zcela ignorují a C++ a různé další jazyky jsou dokonce horší.
Většina raných implementací imaginární paměti RAM, které jsem viděl, řešila velmi specifický případ, kdy jeden velký proces – řekněme 51 %+ dostupné paměti – potřeboval fork()
za účelem exec()
nějaký podpůrný program, obvykle mnohem, mnohem menší. Operační systémy se sémantikou kopírování při zápisu by umožnily fork()
, ale s výhradou, že pokud by se rozvětvený proces skutečně pokusil upravit příliš mnoho paměťových stránek (každá z nich by pak musela být vytvořena jako nová stránka nezávislá na počátečním obrovském procesu), skončilo by to smrtí. Rodičovský proces byl v nebezpečí pouze v případě, že by alokoval více paměti, a mohl zvládnout vyčerpání, v některých případech jen tak, že chvíli počkal, než nějaký jiný proces zemře, a pak pokračoval. Podřízený proces se obvykle jen nahradil (obvykle menším) programem přes exec()
a byl poté osvobozen od výhrady.
Koncepce linuxového overcommit je extrémním přístupem k umožnění obou fork()
aby se vyskytly a zároveň umožnily masivní přetížení jednotlivých procesů. K úmrtím způsobeným vrahem OOM dochází asynchronně, a to i u programů, které dělají zodpovědně zacházet s alokací paměti. Osobně nesnáším celosystémové overcommit obecně a oom-killer konkrétně – podporuje přístup ke správě paměti, který infikuje knihovny a prostřednictvím nich každou aplikaci, která je používá.
Navrhoval bych nastavit poměr na 100 a mít také swapovací oddíl, který by obecně nakonec využívaly pouze obrovské procesy – které často využívají jen nepatrný zlomek své části, která se nacpe do swapu, a tedy chránit drtivou většinu procesů před chybnou funkcí zabijáka OOM. To by mělo ochránit váš webový server před náhodnou smrtí a pokud byl napsán tak, aby zpracovával malloc
zodpovědně, dokonce v bezpečí před sebevraždou (ale nesázejte na to druhé).
To znamená, že to používám v /etc/sysctl.d/10-no-overcommit.conf
vm.overcommit_memory = 2
vm.overcommit_ratio = 100