Wie stoppe ich schnell einen Prozess, der Thrashing verursacht (aufgrund übermäßiger Speicherzuweisung)?


19

Wir alle haben es erlebt - ein Programm muss etwas tun, das sehr viel Speicher benötigt. Es versucht pflichtbewusst, all diesen Speicher zuzuweisen, und das System beginnt sofort zu zermürben, endlos zu tauschen und träge oder nicht mehr reagierend zu werden.

Ich habe das zuletzt auf meinem Ubuntu-Laptop erlebt, weil ein Matlab-Skript versucht hat, eine lächerlich große Matrix zuzuweisen. Nach mehr als 5 Minuten Dreschen konnte ich Strg-F1 an eine Konsole drücken und Matlab töten. Ich hätte viel lieber einen Hotkey, der mir sofort die Kontrolle über das System gegeben hätte und mir erlaubt hätte, den störenden Prozess abzubrechen. oder vielleicht einfach stillschweigend die Zuweisung eines so großen Puffers verweigern.

  1. Was ist der schnellste Weg, um die Kontrolle über ein Linux-System zurückzugewinnen, das aufgrund übermäßigen Austauschs nicht mehr reagiert oder extrem träge ist?

  2. Gibt es einen wirksamen Weg, um ein solches Auslagern zu verhindern, indem beispielsweise die Speichermenge begrenzt wird, die ein Prozess zuzuteilen versucht?

Antworten:


12

Drücken Sie Alt-SysRq-F , um den Prozess mit dem größten Speicherbedarf abzubrechen :

  • Der SysRq-Schlüssel wird normalerweise dem Druckschlüssel zugeordnet.
  • Wenn Sie einen grafischen Desktop verwenden, müssen Sie möglicherweise die Tastenkombination Strg-Alt-SysRq-F drücken, falls durch Drücken der Tastenkombination Alt-SysRq eine andere Aktion ausgelöst wird (z. B. ein Snapshot-Programm).
  • Wenn Sie einen Laptop verwenden, müssen Sie möglicherweise auch eine Funktionstaste drücken.
  • Weitere Informationen finden Sie im Wikipedia-Artikel .

5

Zu diesem Zweck habe ich ein Skript erstellt: https://github.com/tobixen/thrash-protect

Ich habe dieses Skript mit gutem Erfolg auf Produktionsservern, Workstations und Laptops ausgeführt. Dieses Skript bricht Prozesse nicht ab, sondern unterbricht sie vorübergehend. Ich war mir später sicher, dass ich die Kontrolle über sie verloren hätte, wenn dieses einfache Skript nicht verwendet worden wäre. Im "schlimmsten" Fall wird der fehlerhafte Prozess stark verlangsamt und am Ende vom Kernel (OOM) beendet, im "besten" Fall wird der fehlerhafte Prozess tatsächlich abgeschlossen ... auf jeden Fall der Server oder die Workstation wird relativ reaktionsschnell bleiben, so dass es einfach ist, die Situation zu untersuchen.

Natürlich sind "Kaufen Sie mehr Speicher" oder "Verwenden Sie keinen Swap" zwei alternative, traditionellere Antworten auf die Frage "Wie vermeide ich Thrashing?", Aber im Allgemeinen funktionieren sie nicht so gut (möglicherweise wird mehr Speicher installiert) Da dies nicht trivial ist, kann ein Rogue-Prozess den gesamten Arbeitsspeicher aufzehren, unabhängig davon, wie viel er installiert hat, und es kann auch ohne Swap zu Problemen kommen, wenn nicht genügend Arbeitsspeicher zum Puffern / Zwischenspeichern vorhanden ist. Ich empfehle Thrash-Protect plus viel Swap-Platz.


Informationen zum Deaktivieren des Austauschs sind laut unix.stackexchange.com/a/24646/9108 möglicherweise nicht die beste Option.
Sashoalm

In der Tat hat mich jemand gleich kommentiert, also habe ich an diesem Punkt das Thrash-Protect-Dokument geändert.
Tobixen

4
  1. Was ist der schnellste Weg, um die Kontrolle über ein Linux-System zurückzugewinnen, das aufgrund übermäßigen Austauschs nicht mehr reagiert oder extrem träge ist?

Wurde oben bereits mit Alt-SysRq-F beantwortet

  1. Gibt es einen wirksamen Weg, um ein solches Auslagern zu verhindern, indem beispielsweise die Speichermenge begrenzt wird, die ein Prozess zuzuteilen versucht?

Ich beantworte diesen 2. Teil. Ja, ulimitfunktioniert immer noch gut genug, um einen einzelnen Prozess einzuschränken. Sie können:

  • Setzen Sie ein weiches Limit für einen Prozess, von dem Sie wissen, dass er wahrscheinlich außer Kontrolle geraten wird
  • Setzen Sie ein hartes Limit für alle Prozesse, wenn Sie eine zusätzliche Versicherung wünschen

Auch, wie kurz erwähnt:

Sie können CGroups verwenden, um die Ressourcennutzung einzuschränken und solche Probleme zu vermeiden

Cgroups bieten zwar eine erweiterte Steuerung, sind aber meiner Meinung nach derzeit schwieriger zu konfigurieren.

Alte Schule ulimit

Einmalig

Hier ist ein einfaches Beispiel:

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

Es:

  • Legt ein Soft-Limit von 1 GB Gesamtspeicher fest (ulimit geht von einem Limit in KB-Einheiten aus)
  • Führt einen rekursiven Bash-Funktionsaufruf aus r2(){ r2 $@$@;};r2 r2, der die CPU und den RAM exponentiell auslastet, indem er sich beim Anfordern des Stapelspeichers unendlich verdoppelt.

Wie Sie sehen, wurde es angehalten, als versucht wurde, mehr als 1 GB anzufordern.

Beachten Sie, dass -vdie Zuweisung von virtuellem Speicher (insgesamt, dh physisch + Swap) ausgeführt wird.

Permanenter Schutz

Um die Zuweisung asdes virtuellen Speichers zu begrenzen, ist dies das Äquivalent von -vfor limits.conf.

Ich tue Folgendes, um mich vor einem einzelnen Fehlverhalten zu schützen:

  • Legen Sie für alle Prozesse ein festes Adressraumlimit fest.
  • address space limit = <physical memory> - 256MB.
  • Daher kann kein einzelner Prozess mit übermäßiger Speichernutzung oder einer aktiven Schleife und einem Speicherverlust den gesamten physischen Speicher belegen.
  • 256 MB Headroom stehen für die Verarbeitung mit ssh oder einer Konsole zur Verfügung.

Einzeiler:

$ 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"

Für die Validierung ergibt sich Folgendes (z. B. auf einem 16-GB-System):

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

Anmerkungen:

  • Es wird nur verhindert, dass ein einzelner Prozess mit der Speichernutzung überlastet wird.
  • Verhindert nicht, dass ein Multi-Prozess-Workload mit hohem Speicherdruck zu Thrashing führt (cgroups ist dann die Antwort).
  • Verwenden Sie nicht die rssOption in der limits.conf. Es wird von neueren Kerneln nicht respektiert.
  • Es ist konservativ.
    • Theoretisch kann ein Prozess viel Speicher spekulativ anfordern, jedoch nur eine Teilmenge aktiv verwenden (kleinere Arbeitsmenge / residente Speichernutzung).
    • Durch die oben angegebene Beschränkung werden solche Prozesse abgebrochen (auch wenn sie unter Linux möglicherweise fehlerfrei ausgeführt werden, kann der Adressraum des virtuellen Speichers überlastet werden).

Neuere CGruppen

Bietet mehr Kontrolle, ist aber derzeit komplexer zu bedienen:

  • Verbessert das ulimit-Angebot.
    • memory.max_usage_in_bytes kann den physischen Speicher separat erfassen und begrenzen.
    • Zwar sollte ulimit -mund / oder rssin limits.confeine ähnliche Funktionalität bieten, aber das funktioniert seit Kernel Linux 2.4.30 nicht mehr!
  • Need einige Kernel cgroup Fahnen in Bootloader aktivieren: cgroup_enable=memory swapaccount=1.
    • Dies war bei Ubuntu 16.04 standardmäßig nicht der Fall.
    • Wahrscheinlich aufgrund einiger Auswirkungen auf die Leistung durch zusätzlichen Aufwand für die Buchhaltung.
  • cgroup / systemd-Zeug ist relativ neu und ändert sich ein wenig, daher impliziert der Upstream-Fluss, dass Linux-Distributoren es noch nicht einfach gemacht haben, es zu verwenden. Zwischen 14.04LTS und 16.04LTS wurde das User-Space-Tool zur Verwendung von cgroups geändert.
    • cgm Jetzt scheint es sich um das offiziell unterstützte Userspace-Tool zu handeln.
    • System-Unit-Dateien scheinen noch keine vordefinierten "Vendor / Distro" -Standards zu haben, um wichtige Dienste wie ssh zu priorisieren.

ZB um die aktuellen Einstellungen zu überprüfen:

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

ZB um den Speicher eines einzelnen Prozesses einzuschränken:

$ 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

Um zu sehen, wie RAM als Hintergrundprozess gekaut und dann getötet wird, gehen Sie wie folgt vor:

$ 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'

Beachten Sie das exponentielle Wachstum (Potenz 2) der Speicheranforderungen.

Hoffen wir, dass in Zukunft "Distributoren / Lieferanten" Prioritäten und Limits für C-Gruppen (über System-Einheiten) für wichtige Dinge wie SSH und den Grafikstapel vorkonfigurieren, sodass ihnen nie der Speicher ausgeht.


2

Möglicherweise können Sie Ctrl- drücken z, um das Programm anzuhalten. Dann können Sie kill %1(oder wie auch immer die Auftragsnummer lautet oder Sie können die PID verwenden).

Mit dem ulimitBefehl können Sie versuchen, den für einen Prozess verfügbaren Speicherplatz zu begrenzen.


Strg-Z ist nett, aber normalerweise verwende ich eine Matlab-Benutzeroberfläche und habe den Überblick über das steuernde Terminal verloren. Daher ist es nicht einfach, den Strg-Z-Tastendruck auszugeben. Es wäre schön, wenn die GUI einen Tastenkürzel hätte, um SIGSTOP an eine beliebige Anwendung zu senden, die den Fokus hat!
Nibot

Sie können ausführen, kill -STOP <pid>was dasselbe bewirkt wie Strg-Z.
hlovdal

Ja, aber das ganze Problem ist, dass das System in einer solchen Situation so nicht reagiert, dass es lange (oder ewig) dauert, bis eine Eingabeaufforderung angezeigt wird.
Nibot

1

Sie können CGroups verwenden, um die Ressourcennutzung einzuschränken und solche Probleme zu vermeiden: https://en.wikipedia.org/wiki/Cgroups


Bitte geben Sie die wesentlichen Informationen in Ihrer Antwort an und verwenden Sie den Link nur zur Namensnennung und weiteren Lektüre. Dieser Link beschreibt, was CGroups sind, aber aus dem Link ist nicht ersichtlich, wie man es tatsächlich verwendet, um das Problem zu lösen. Können Sie Ihre Antwort erweitern, um die Lösung der Frage zu beschreiben? Vielen Dank.
Fixer1234

0

Es wäre schön, wenn die GUI einen Tastenkürzel hätte, um SIGSTOP an eine beliebige Anwendung zu senden, die den Fokus hat!

Es gibt immer den klassischen xkillBefehl (von xorg-x11-apps-7.4-14.fc14.src.rpm auf meinem System). Ich denke, es sollte nicht zu schwierig sein, einen Klon zu erstellen, der SIGSTOP sendet, anstatt das Zielfenster zu beenden.


Wie kann ich xkill durch Drücken einer Tastenkombination schnell starten lassen?
Nibot

Ich bin mir nicht sicher. Ich gehe davon aus, dass sowohl Gnome als auch KDE einige globale Verknüpfungsfunktionen haben, die zum Starten von Programmen verwendet werden können.
24.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.