Uruchomiłem skrypt powłoki z poleceniami, aby uruchomić kilka programów intensywnie korzystających z pamięci (2-5 GB) jeden za drugim. Gdy wróciłem, aby sprawdzić postępy w skrypcie, z zaskoczeniem odkryłem, że niektóre z moich procesów przebiegały Killed
zgodnie z raportem mojego terminalu. Kilka programów zakończyło się już sukcesywnie przed programami, które zostały później Killed
uruchomione, ale wszystkie te programy później uległy awarii w wyniku segmentacji (która mogła, ale nie musi być spowodowana błędem w moim kodzie, czytaj dalej).
Przejrzałem historię użytkowania konkretnego klastra, z którego korzystałem, i zobaczyłem, że ktoś zaczął uruchamiać kilka procesów intensywnie wykorzystujących pamięć w tym samym czasie i w ten sposób wyczerpał rzeczywistą pamięć (a być może nawet przestrzeń wymiany) dostępną dla klastra. O ile wiem, te procesy wymagające dużej ilości pamięci zaczęły działać mniej więcej w tym samym czasie, gdy zaczęły się problemy z moimi programami.
Czy to możliwe, że Linux zabił moje programy, gdy zabrakło pamięci? Czy to możliwe, że błędy segmentacji, które dostałem później, były spowodowane brakiem pamięci dostępnej do uruchamiania moich programów (zamiast błędu w kodzie)?
źródło
Odpowiedzi:
To może.
Istnieją dwa różne warunki braku pamięci, które można napotkać w systemie Linux. Spotkanie zależy od wartości
sysctl vm.overcommit_memory
(/proc/sys/vm/overcommit_memory
)Wprowadzenie:
Jądro może wykonywać tak zwane „overcommit pamięci”. To wtedy jądro przydziela programom więcej pamięci, niż jest w rzeczywistości w systemie. Odbywa się to w nadziei, że programy faktycznie nie wykorzystają całej przydzielonej pamięci, ponieważ jest to dość częste zjawisko.
overcommit_memory = 2
Kiedy
overcommit_memory
jest ustawiony na2
, jądro w ogóle nie wykonuje żadnego nadpisywania. Zamiast tego, gdy program ma przydzieloną pamięć, zagwarantowany jest dostęp do tej pamięci. Jeśli system nie ma wystarczającej ilości wolnej pamięci, aby zaspokoić żądanie alokacji, jądro po prostu zwróci błąd dla żądania. Program w pełni wdzięcznie poradzi sobie z sytuacją. Jeśli nie sprawdzi, czy alokacja się powiodła, gdy naprawdę się nie powiodła, aplikacja często napotyka awarię.W przypadku segfault powinieneś znaleźć taką linię na wyjściu
dmesg
:Te
at 0
środki, które aplikacja próbowali uzyskać dostęp do niezainicjowanej wskaźnik, który może być wynikiem nieudanego wezwania alokacji pamięci (ale nie jest to jedyna droga).overcommit_memory = 0 i 1
Gdy
overcommit_memory
jest ustawiony na0
lub1
, funkcja overcommit jest włączona, a programy mogą przydzielać więcej pamięci, niż jest w rzeczywistości dostępne.Jednak, gdy program chce użyć pamięci, która została przydzielona, ale jądro stwierdza, że tak naprawdę nie ma wystarczającej ilości pamięci, aby ją zaspokoić, musi odzyskać trochę pamięci. Najpierw próbuje wykonać różne zadania czyszczenia pamięci, takie jak opróżnianie pamięci podręcznej, ale jeśli to nie wystarczy, przerwie proces. To zakończenie jest wykonywane przez OOM-Killera. OOM-Killer patrzy na system, aby zobaczyć, które programy używają jakiej pamięci, jak długo działały, kto je uruchamia, oraz szereg innych czynników, aby ustalić, który z nich zostanie zabity.
Po tym, jak proces został zabity, używana pamięć zostaje zwolniona, a program, który właśnie spowodował stan braku pamięci, ma teraz potrzebną pamięć.
Jednak nawet w tym trybie programom nadal można odmówić żądania alokacji. Kiedy
overcommit_memory
jest0
, jądro próbuje zgadnąć, kiedy powinien zacząć odrzucać żądania alokacji. Gdy jest ustawiony na1
, nie jestem pewien, jakiej determinacji używa, aby określić, kiedy powinien odrzucić żądanie, ale może odrzucić bardzo duże żądania.Możesz sprawdzić, czy OOM-Killer jest zaangażowany, patrząc na wyniki
dmesg
i znajdując komunikaty, takie jak:źródło
overcommit_memory
jest ustawiony na 0 lub 2.overcommit_memory=2
zabójca OOM nie jest nawet włączony, więc kontrolowanie go nie ma znaczenia. Jednak gdy ustalimy, że jest to zabójca OOM, staje się on kolejnym tematem, który obejmuje wiele innych pytań i odpowiedzi tutaj.Prawda jest taka, że bez względu na to, jak na to patrzysz - niezależnie od tego, czy proces został uduszony z powodu menedżera pamięci systemu, czy z innego powodu - nadal jest to błąd. Co się stało z tymi wszystkimi danymi, które właśnie przetwarzałeś w pamięci? Powinien był zostać uratowany.
Chociaż
overcommit_memory=
jest to najbardziej ogólny sposób konfigurowania zarządzania Linux OOM, można go również dostosowywać do poszczególnych procesów, takich jak:Zastosowanie
-17
powyższego spowoduje wykluczenie procesu z zarządzania brakiem pamięci. Prawdopodobnie ogólnie nie jest to świetny pomysł, ale jeśli polujesz na robaki, warto to zrobić - szczególnie jeśli chcesz wiedzieć, czy to OOM, czy kod. Dodatnie zwiększenie liczby zwiększy prawdopodobieństwo zabicia procesu w zdarzeniu OOM, co może pomóc w lepszym wzmocnieniu odporności kodu w sytuacjach o niskiej pamięci i zapewnić, że w razie potrzeby wyjdziesz z gracją.Możesz sprawdzić bieżące ustawienia modułu obsługi OOM dla każdego procesu, na przykład:
W przeciwnym razie możesz popełnić samobójstwo:
Spowoduje to ponowne uruchomienie komputera w przypadku braku pamięci. Ustawiasz
X
powyższe na liczbę sekund, po których komputer ma się zatrzymać po panice jądra przed ponownym uruchomieniem. Zaszaleć.A jeśli z jakiegoś powodu zdecydujesz, że ci się podoba, spraw, aby był trwały:
źródło