Jak szybko zatrzymać proces powodujący przeładowanie (z powodu nadmiernej alokacji pamięci)?

19

Wszyscy tego doświadczyliśmy - jakiś program jest proszony o zrobienie czegoś, co wymaga ogromnej ilości pamięci. Sumiennie próbuje przydzielić całą tę pamięć, a system natychmiast zaczyna bić, zamieniać bez końca i staje się powolny lub nie reaguje.

Ostatnio doświadczyłem tego na moim laptopie z Ubuntu, ponieważ skrypt Matlab próbuje przydzielić absurdalnie ogromną matrycę. Po około 5 + minutach thrashingu byłem w stanie Ctrl-F1 na konsoli i zabić Matlaba. Wolałbym mieć jakiś skrót klawiszowy, który dałby mi natychmiast kontrolę nad systemem i pozwolił mi zabić przestępcę; a może po prostu w milczeniu odmawiają przydzielenia tak dużego bufora.

  1. Jaki jest najszybszy sposób na odzyskanie kontroli nad systemem Linux, który przestał reagować lub był bardzo powolny z powodu nadmiernej wymiany?

  2. Czy istnieje skuteczny sposób, aby przede wszystkim zapobiec takiej zamianie, na przykład poprzez ograniczenie ilości pamięci, którą proces może przydzielić?

nibot
źródło

Odpowiedzi:

12

Naciśnij klawisze Alt-SysRq-F, aby zabić proces przy użyciu największej ilości pamięci:

  • Klucz SysRq jest zwykle mapowany na klawisz Drukuj.
  • Jeśli korzystasz z pulpitu graficznego, może być konieczne naciśnięcie klawiszy Ctrl-Alt-SysRq-F na wypadek, gdyby naciśnięcie Alt-SysRq wyzwoliło inną akcję (np. Program do wykonywania migawek).
  • Jeśli używasz laptopa, może być konieczne naciśnięcie klawisza funkcyjnego.
  • Aby uzyskać więcej informacji, przeczytaj artykuł w Wikipedii .
żart
źródło
5

Stworzyłem w tym celu skrypt - https://github.com/tobixen/thrash-protect

Skrypt ten działał z powodzeniem na serwerach produkcyjnych, stacjach roboczych i laptopach. Ten skrypt nie zabija procesów, ale zawiesza je tymczasowo - miałem kilka sytuacji później, w których jestem pewien, że straciłem kontrolę z powodu thrashingu, gdyby nie ten prosty skrypt. W „najgorszym” przypadku przestępstwo zostanie znacznie spowolnione i ostatecznie zostanie zabite przez jądro (OOM), w „najlepszym” przypadku przestępstwo faktycznie się zakończy ... w każdym razie serwer lub stacja robocza pozostanie stosunkowo wrażliwy, aby łatwo było zbadać sytuację.

Oczywiście, „kup więcej pamięci” lub „nie używaj swapu” to dwie alternatywne, bardziej tradycyjne odpowiedzi na pytanie „jak uniknąć przeładowania?”, Ale generalnie nie działają tak dobrze (instalowanie większej ilości pamięci może nie jest trywialny, nieuczciwy proces może pochłonąć całą pamięć bez względu na to, ile zainstalowałeś, i możesz wpaść w problemy z thrashowaniem nawet bez zamiany, gdy nie ma wystarczającej ilości pamięci do buforowania / buforowania). Polecam thrash-protect plus dużo swapów.

tobixen
źródło
Jeśli chodzi o wyłączenie wymiany, według unix.stackexchange.com/a/24646/9108 może to nie być najlepsza opcja.
sashoalm
Rzeczywiście, ktoś skomentował to samo, więc zmodyfikowałem dokument ochrony przed thrashem.
tobixen
4
  1. Jaki jest najszybszy sposób na odzyskanie kontroli nad systemem Linux, który przestał reagować lub był bardzo powolny z powodu nadmiernej wymiany?

Już odpowiedziałem powyżej za pomocą Alt-SysRq-F

  1. Czy istnieje skuteczny sposób, aby przede wszystkim zapobiec takiej zamianie, na przykład poprzez ograniczenie ilości pamięci, którą proces może przydzielić?

Odpowiadam na drugą część. Tak, ulimitnadal działa wystarczająco dobrze, aby ograniczyć pojedynczy proces. Możesz:

  • ustaw miękki limit dla procesu, o którym wiesz, że prawdopodobnie wymknie się spod kontroli
  • ustaw sztywny limit dla wszystkich procesów, jeśli chcesz uzyskać dodatkowe ubezpieczenie

Ponadto, jak krótko wspomniano:

Możesz użyć CGroups, aby ograniczyć wykorzystanie zasobów i zapobiec takim problemom

Rzeczywiście, cgroups oferują bardziej zaawansowaną kontrolę, ale obecnie moim zdaniem są bardziej skomplikowane w konfiguracji.

Old school ulimit

Raz wolny

Oto prosty przykład:

$ bash
$ ulimit -S -v $((1*2**20))
$ r2(){r2 $@$@;};r2 r2
bash: xmalloc: .././subst.c:3550: cannot allocate 134217729 bytes (946343936 bytes allocated)

To:

  • Ustawia miękki limit całkowitego wykorzystania pamięci 1 GB (ulimit zakłada limit w jednostkach kB)
  • Uruchamia rekurencyjne wywołanie funkcji bash r2(){ r2 $@$@;};r2 r2, która wykładniczo przeżuwa procesor i pamięć RAM, nieskończenie podwajając się podczas żądania pamięci stosu.

Jak widać, został zatrzymany podczas próby żądania więcej niż 1 GB.

Uwaga, -vdziała na zasadzie alokacji pamięci wirtualnej (ogółem, tj. Fizyczna + zamiana).

Stała ochrona

Aby ograniczyć alokacji pamięci wirtualnej asjest równoważny -vdla limits.conf.

Wykonuję następujące czynności, aby zabezpieczyć się przed jakimkolwiek niewłaściwym procesem:

  • Ustaw sztywny limit przestrzeni adresowej dla wszystkich procesów.
  • address space limit = <physical memory> - 256MB.
  • Dlatego żaden pojedynczy proces z chciwym wykorzystaniem pamięci lub aktywną pętlą i przeciekiem pamięci nie może zająć CAŁEJ pamięci fizycznej.
  • 256 MB miejsca jest potrzebne do niezbędnego przetwarzania za pomocą ssh lub konsoli.

Jedna wkładka:

$ sudo bash -c "echo -e \"*\thard\tas\t$(($(grep -E 'MemTotal' /proc/meminfo | grep -oP '(?<=\s)\d+(?=\skB$)') - 256*2**10))\" > /etc/security/limits.d/mem.conf"

Aby sprawdzić poprawność, wynik jest następujący (np. W systemie 16 GB):

$ cat /etc/security/limits.d/mem.conf
*   hard    as      16135196
$ ulimit -H -v
161351960

Uwagi:

  • Łagodzi tylko jeden proces, który przesadza z wykorzystaniem pamięci.
  • Nie zapobiegnie obciążeniu wieloprocesowemu przy dużej presji pamięci powodującej przeładowanie (wtedy cgroups jest odpowiedzią).
  • Nie używaj rssopcji w limit.conf. Nie jest szanowany przez nowsze jądra.
  • To jest konserwatywne.
    • Teoretycznie proces może spekulacyjnie żądać dużej ilości pamięci, ale tylko aktywnie korzysta z podzbioru (mniejsze użycie zestawu roboczego / pamięci rezydentnej).
    • Powyższy sztywny limit spowoduje przerwanie takich procesów (nawet jeśli mogłyby one działać poprawnie, ponieważ Linux pozwala na nadmierne wykorzystanie przestrzeni adresowej pamięci wirtualnej).

Nowsze grupy C

Oferuje większą kontrolę, ale obecnie jest bardziej skomplikowany w użyciu:

  • Poprawiono ofertę ulimit.
    • memory.max_usage_in_bytes może osobno rozliczać i ograniczać pamięć fizyczną.
    • Natomiast ulimit -mi / lub rssin limits.confmiał oferować podobną funkcjonalność, ale to nie działa od jądra Linuksa 2.4.30!
  • Potrzeba, aby umożliwić pewne flagi cgroup jądro bootloader: cgroup_enable=memory swapaccount=1.
    • Nie zdarzyło się to domyślnie w Ubuntu 16.04.
    • Prawdopodobnie z powodu pewnych skutków dodatkowych kosztów księgowych związanych z wydajnością.
  • cgroup / systemd stuff jest stosunkowo nowy i zmienia się nieco, więc flux upstream sugeruje, że dostawcy dystrybucji Linuksa jeszcze nie ułatwili jego obsługi. Pomiędzy 14.04LTS a 16.04LTS zmieniło się oprzyrządowanie przestrzeni użytkownika do korzystania z cgroups.
    • cgm teraz wydaje się być oficjalnie obsługiwanym narzędziem przestrzeni użytkownika.
    • Wydaje się, że w plikach jednostek systemowych nie ma żadnych wstępnie zdefiniowanych wartości domyślnych „dostawca / dystrybucja”, aby nadać priorytet ważnym usługom, takim jak ssh.

Np. Aby sprawdzić bieżące ustawienia:

$ echo $(($(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes) / 2**20)) MB
11389 MB
$ cat /sys/fs/cgroup/memory/memory.stat
...

Np. Aby ograniczyć pamięć pojedynczego procesu:

$ cgm create memory mem_1G
$ cgm setvalue memory mem_1G memory.limit_in_bytes $((1*2**30))
$ cgm setvalue memory mem_1G memory.memsw.limit_in_bytes $((1*2**30))
$ bash
$ cgm movepid memory mem_1G $$
$ r2(){ r2 $@$@;};r2 r2
Killed

Aby zobaczyć, jak działa, przeżuwa pamięć RAM jako proces w tle, a następnie ginie:

$ bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2' & while [ -e /proc/$! ]; do ps -p $! -o pcpu,pmem,rss h; sleep 1; done
[1] 3201
 0.0  0.0  2876
 102  0.2 44056
 103  0.5 85024
 103  1.0 166944
 ...
98.9  5.6 920552
99.1  4.3 718196
[1]+  Killed                  bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2'

Zwróć uwagę na wykładniczy (potęga 2) wzrost liczby żądań pamięci.

W przyszłości zobaczmy, jak „dystrybucja / dostawcy” wstępnie konfigurują priorytety i limity grupy (za pomocą jednostek systemowych) dla ważnych rzeczy, takich jak SSH i stos graficzny, tak aby nigdy nie brakowało im pamięci.

JPvRiel
źródło
2

Możesz nacisnąć Ctrl-, zaby zawiesić program. Następnie możesz to zrobić kill %1(niezależnie od tego, jaki jest numer zadania lub możesz użyć PID).

Możesz użyć tego ulimitpolecenia, aby spróbować ograniczyć ilość pamięci dostępnej dla procesu.

Wstrzymano do odwołania.
źródło
Ctrl-Z jest fajny, ale zazwyczaj uruchamiam GUI Matlaba i straciłem kontrolę nad terminalem kontrolnym, więc nie mam łatwego sposobu na wydanie klawisza Ctrl-Z. Byłoby miło, gdyby GUI posiadało klawisz skrótu do wysyłania SIGSTOP do dowolnej aplikacji, na której się koncentruje!
nibot
Możesz uruchomić, kill -STOP <pid>który zrobi to samo co Ctrl-Z.
hlovdal
Tak, ale cały problem polega na tym, że w takiej sytuacji system nie reaguje tak szybko, że dotarcie do wiersza polecenia zajmuje dużo czasu (lub zawsze).
nibot
1

Możesz użyć CGroups, aby ograniczyć wykorzystanie zasobów i zapobiec takim problemom: https://en.wikipedia.org/wiki/Cgroups

1kenthomas
źródło
Podaj istotne informacje w swojej odpowiedzi i użyj linku tylko do przypisania i dalszego czytania. Ten link opisuje, czym są CGroups, ale nie jest oczywiste z linku, jak faktycznie użyć go do rozwiązania problemu. Czy potrafisz rozszerzyć swoją odpowiedź, aby opisać rozwiązanie pytania? Dzięki.
fixer1234
0

Byłoby miło, gdyby GUI posiadało klawisz skrótu do wysyłania SIGSTOP do dowolnej aplikacji, na której się koncentruje!

Zawsze jest klasyczne xkillpolecenie (z xorg-x11-apps-7.4-14.fc14.src.rpm w moim systemie). Wydaje mi się, że stworzenie klona, ​​który wysyła SIGSTOP, zamiast zabijać okno docelowe, nie powinno być zbyt trudne.

hlovdal
źródło
Jak mogę szybko uruchomić xkill po naciśnięciu jakiejś kombinacji klawiszy?
nibot
Nie jestem pewien. Zakładam, że zarówno gnome, jak i KDE mają pewne globalne funkcje skrótów, których można używać do uruchamiania programów.
hlovdal