Rozdział 9.6 „Overcommit and OOM” w dokumencie, o którym wspomina @dunxd, jest szczególnie graficzny na temat niebezpieczeństw związanych z dopuszczeniem overcommit. Jednak 80wyglądało to również dla mnie interesująco, więc przeprowadziłem kilka testów.
Odkryłem, że overcommit_ratiowpływa na całkowitą pamięć RAM dostępną dla WSZYSTKICH procesów. Procesy rootowania nie wydają się być traktowane inaczej niż zwykłe procesy użytkownika.
Ustawienie współczynnika na 100lub mniej powinno zapewnić klasyczną semantykę, w której wartości zwracane malloc/sbrksą wiarygodne. Ustawienie niższych współczynników 100może być sposobem na zarezerwowanie większej ilości pamięci RAM na działania niezwiązane z procesem, takie jak buforowanie i tak dalej.
Tak więc na moim komputerze z 24 GiB RAM, z wyłączoną zamianą, 9 GiB w użyciu, z topwyświetlaniem
Mem: 24683652k total, 9207532k used, 15476120k free, 19668k buffers
Swap: 0k total, 0k used, 0k free, 241804k cached
Oto niektóre overcommit_ratioustawienia i ilość pamięci RAM, którą mój program RAM-konsument może pobrać (dotykając każdej strony) - w każdym przypadku program wyszedł poprawnie po mallocawarii.
50 ~680 MiB
60 ~2900 MiB
70 ~5200 MiB
100 ~12000 MiB
Uruchamianie kilku jednocześnie, nawet z niektórymi użytkownikami root, nie zmieniło łącznej kwoty, którą zużyli razem. Interesujące jest to, że nie był w stanie zużyć ostatnich 3+ GiB; freenie spadnie znacznie poniżej tego, co jest pokazane tutaj:
Mem: 24683652k total, 20968212k used, 3715440k free, 20828k buffers
Eksperymenty były chaotyczne - wszystko, co korzysta z malloc w chwili, gdy cała pamięć RAM jest w użyciu, ma tendencję do zawieszania się, ponieważ wielu programistów obawia się sprawdzania błędów malloc w C, niektóre popularne biblioteki kolekcji ignorują to całkowicie, a C ++ i różne inne języki są nawet gorzej.
Większość wczesnych implementacji wyobrażonej pamięci RAM dotyczyła bardzo konkretnego przypadku, w którym jeden duży proces - powiedzmy ponad 51% dostępnej pamięci - był potrzebny fork(), aby exec()jakiś program wsparcia, zwykle o wiele, znacznie mniejszy. Systemy operacyjne z semantyką kopiowania przy zapisie pozwoliłyby na to fork(), ale pod warunkiem, że jeśli rozwidlony proces faktycznie spróbuje zmodyfikować zbyt wiele stron pamięci (każda z nich musiałaby zostać utworzona jako nowa strona niezależna od początkowego ogromnego procesu) w końcu zostanie zabity. Proces nadrzędny był zagrożony tylko przy przydzielaniu większej ilości pamięci i mógł poradzić sobie z wyczerpaniem, w niektórych przypadkach po prostu czekając trochę na śmierć innego procesu, a następnie kontynuując. Proces potomny zwykle po prostu zastępuje się (zwykle mniejszym) programem przezexec() i wtedy był wolny od zastrzeżenia.
Nadmierna koncepcja Linuksa jest ekstremalnym podejściem pozwalającym zarówno na fork()wystąpienie, jak i na masową ogólną alokację pojedynczych procesów. Zgony OOM-killer-spowodowane zdarzyć asynchronicznie, nawet do programów, które zrobienia alokacji pamięci uchwyt odpowiedzialnie. Ja osobiście nienawidzę nadmiernego zaangażowania całego systemu, a szczególnie zabójcy zagłady - sprzyja to diabelnie ostrożnemu podejściu do zarządzania pamięcią, które infekuje biblioteki i za ich pośrednictwem każdą aplikację, która ich używa.
Sugeruję ustawienie współczynnika na 100, a także posiadanie partycji wymiany, która na ogół kończy się przyzwyczajeniem się przez ogromne procesy - które często wykorzystują tylko niewielką część siebie, która zostaje upchnięta w swap, a zatem chronić ogromną większość procesów przed błędami zabójcy OOM. To powinno zabezpieczyć twój serwer przed przypadkową śmiercią, a jeśli został napisany z myślą o mallocodpowiedzialnym postępowaniu , nawet bezpieczny przed samobójstwem (ale nie stawiaj na to drugie).
To znaczy, że używam tego w /etc/sysctl.d/10-no-overcommit.conf
vm.overcommit_memory = 2
vm.overcommit_ratio = 100