Der Linux-Kernel steuert so gut wie alles, was unter ihm läuft – also alles, auch den Speicher (Hauptspeicher oder auch RAM genannt). Ein Computer kann noch so viel RAM haben, wenn eine Software durch einen Fehler immer mehr solchen braucht, ist der RAM irgendwann zu Ende. Dann muss der Kernel irgend etwas tun (nicht nur der Linux-Kernel, sondern auch der von Windows oder macOS) – er wird einen Prozess beenden, um dem restlichen Betriebssystem wieder mehr RAM zur Verfügung stellen zu können – hat dieses zu wenig, steht die Kiste ganz einfach und dies muss vermieden werden.

Der Prozess, der in diesem Fall Prozesse beendet, nennt sich Out Of Memory-Killer, oder kurz einfach OOM. In den meisten Fällen wird OOM ganz einfach den Prozess killen, der am meisten RAM benötigt. Schlimm ist dies etwa auf einem Server, dessen Webseite etwa eine Datenbank benötigt – ohne die DB funktioniert die Webseite nicht.

Wie wählt der OOM-Killer entsprechende Prozesse aus?

Der OOM-Killer wählt zu beendende Prozesse nach einem Score aus, diese sucht er sich aus dem Systemverzeichnis „/proc“ (hierzu sind root-Rechte nötig):

ls /proc/

Jeder Prozess hat hier sein eigenes Verzeichnis mit einer Nummer, in jedem solchen Verzeichnis finden sich einige Dateien – etwa:

ls /proc/174/

Unter anderem findet sich in einem solchen Verzeichnis eine Datei Namens „oom_score„, diese beinhaltet einen Score, nachdem OOM auswählt, ob dieser Prozess beendet wird oder nicht. Sehen wir uns den Inhalt der Datei dieses zufälligen Prozesses einmal an:

less /proc/174/oom_score

Die Zahl in dieser Datei, ist der Score, nachdem OOM zu beendende Prozesse auswählt. Je höher der Score, desto eher wird OOM diesen Prozess bei mangelndem Speicher beenden. Dies war nur ein kleiner Einblick in die Technik – Sie können sich die Prozesse mit folgendem Befehl anzeigen lassen, welche OOM am ehesten beenden wird – mit head -n Zahl geben Sie die Anzahl der Prozesse an:

for pid in $(ls -d /proc/[0-9]* | cut -d/ -f3); do   if [ -r "/proc/$pid/oom_score" ]; then     printf "%-8s %-8s %s\n" "$pid" "$(cat /proc/$pid/oom_score)" "$(cat /proc/$pid/comm 2>/dev/null)";   fi; done | sort -k2 -nr | head -n 10

Der Befehl sort sortiert die Ausgabe in Spalten – die erste zeigt die PID (Prozess-ID), die zweite den Score und die dritte den Prozess-Namen.

Mit folgendem Befehl sehen Sie den Score direkt an zweiter Stelle – mit head -Zahl steuern Sie die Anzahl der ausgegebenen Prozesse:

for p in /proc/[0-9]*; do printf '%s %s %s\n' "$(cat $p/oom_score 2>/dev/null)" "$(cat $p/oom_score_adj 2>/dev/null)" "$(cat $p/comm 2>/dev/null)"; done | sort -rn | head -5

Ein kleines Stück weiter in der Technik – im Verzeichnis findet sich auch eine Datei Namens „oom_score_adj„, diese dient dazu, den Score selbst zu verändern – wurde nichts angepasst, ist der Wert darin „0“.

OOM-Killer nutzen

Jetzt nehmen wir einmal an, Ihre Webseite (oder was auch immer) funktioniert auf einmal nicht mehr – jetzt gilt es erst einmal herauszufinden, ob OOM-Killer dahinter steckt. Versuchen wir es einfach einmal mit dem Prozess „apache2“ oder „php-fpm8.1„:

journalctl -k -g 'oom-killer|apache2'
journalctl -k -g 'oom-killer|php-fpm8.1'

Ob OOM-Killer überhaupt schon einmal zugeschlagen hat, sehen Sie mit:

journalctl -k -g 'oom-killer'

Eine mögliche Ausgabe, wenn die Software zugeschlagen hat:

Oct 21 02:14:07 kernel: php-fpm8.1 invoked oom-killer: gfp_mask=0x140cca(GFP_HIGHUSER_MOVABLE|__GFP_COMP), order=0, oom_score_adj=0
Oct 21 02:14:07 kernel: Out of memory: Killed process 1187 (mariadbd) total-vm:2457316kB, anon-rss:1201344kB, file-rss:0kB, shmem-rss:0kB, UID:107 pgtables:2876kB oom_score_adj:0

Wenn Sie verhindern wollen, das OOM einen Prozess killt, der unbedingt weiterlaufen soll, müssen Sie erst einmal wissen, wie dessen Score aussieht. Ein Beispiel für den Prozess „chrome„:

choom -p $(pgrep -o chrome)

Oder für alle möglichen Chrome-Instanzen:

for pid in $(pidof chrome); do   choom -p "$pid"; done

Jetzt können Sie den Score manuell verändern – die Werte reichen von „-1000 (nie beenden), über „1000“ (gleichgültig) und „+1000“ (sofort bei Problemen beenden).

choom -p $(pidof chrome) -n -1000

Oder für alle Instanzen:

for pid in $(pidof chrome); do; choom -p "$pid" -n -1000; done

Solche Manipulationen halten bis zum nächsten Neustart des Systems. Möchten Sie Einstellungen dauerhaft setzen, müssen Sie etwas tiefer greifen – sehen wir uns in diesem Beispiel die Systemd-Unit „cups“ an:

systemctl show cups -p OOMScoreAdjust

Ein Beispiel für die Ausgabe:

Möchten Sie dessen Score anpassen, bearbeiten Sie die Systemd-Datei des Prozesses, am schnellsten ganz einfach für die genannte Unit:

systemctl edit cups.service

Standard in diesem Fall:

### Editing /etc/systemd/system/cups.service.d/override.conf
### Anything between here and the comment below will become the contents of the drop-in file



### Edits below this comment will be discarded


### /usr/lib/systemd/system/cups.service
# [Unit]
# Description=CUPS Scheduler
# Documentation=man:cupsd(8)
# After=network.target nss-user-lookup.target time-set.target nslcd.service
# Requires=cups.socket
# 
# [Service]
# ExecStart=/usr/sbin/cupsd -l
# Type=notify
# Restart=on-failure
# Slice=system-cups.slice
# 
# 
# [Install]
# Also=cups.socket cups.path
# WantedBy=printer.target multi-user.target

Im Bereich „[Service]“ fügen Sie jetzt als erste Zeile neu hinzu und geben den gewünschten Score an, im Beispiel „-1000„:

### Editing /etc/systemd/system/cups.service.d/override.conf
### Anything between here and the comment below will become the contents of the drop-in file



### Edits below this comment will be discarded


### /usr/lib/systemd/system/cups.service
# [Unit]
# Description=CUPS Scheduler
# Documentation=man:cupsd(8)
# After=network.target nss-user-lookup.target time-set.target nslcd.service
# Requires=cups.socket
# 
# [Service]
OOMScoreAdjust=-1000
# ExecStart=/usr/sbin/cupsd -l
# Type=notify
# Restart=on-failure
# Slice=system-cups.slice
# 
# 
# [Install]
# Also=cups.socket cups.path
# WantedBy=printer.target multi-user.target

Anschließend starten Sie den Service neu.

Den Speicher begrenzen

Jetzt haben wir aber noch immer ein Problem – OOM wird den Prozess zwar nicht beenden, er wird aber auf Grund welchen Fehlers auch immer (siehe etwa die letzten beiden PHP-Lücken) nicht beenden, wenn der Speicher ausgeht, sondern erst andere. Aber wenn der eine Prozess immer mehr RAM benötigt, wird er einmal von selbst abstürzen, weil eben einmal kein freier RAM mehr da ist.

Wir müssen dem Prozess also etwa eine RAM-Grenze vorgeben. Dies funktioniert am einfachsten, wenn das Betriebssystem „cgroups v2“ nutzt, dies zeigt der Befehl:

stat -fc %T /sys/fs/cgroup

Die Ausgabe cgroup2fs bestätigt dies. Um dem Service mit einer Speichergrenze zu belegen nutzen wir wieder Systemd. Im Beispiel mit dem Service „php-fpm8.1“ und einer weichen Grenze von „1,5GB“ und einer harten Grenze von „2GB„:

systemctl set-property php-fpm8.1.service MemoryHigh=1.5G MemoryMax=2G
  • MemoryHigh= – die weiche Grenze. Überschreitet der Prozess diese gesetzte Grenze, beendet der Kernel andere Prozesse, für die keine Grenze gesetzt ist und weniger wichtig sind.
  • MemoryMax= – die harte Grenze. Ab dieser Grenze werden keine anderen Prozesse mehr beendet – der Prozess bekommt einfach nicht mehr. Der Prozess wird zwar langsamer arbeiten, aber trotzdem kaum abstürzen.

Sie können sich gesetzte Grenzen natürlich auch anzeigen lassen, mit demselben Service:

systemctl show php-fpm8.1.service -p MemoryHigh -p MemoryMax

Speichergrenzen testen

Sie können Speichergrenzen auch testen, bevor Sie solche aktivieren. Beispielsweise wieder mit dem oben genannten Service, hier jedoch zusätzlich mit einer Swap-Grenze (so nutzt das Service wirklich nur den RAM und kann nicht in den Auslagerungsspeicher auslagern):

systemd-run --unit=php-fpm8.1 -p MemoryHigh=1.5G MemoryMax=2G -p MemorySwapMax=0 tail /dev/zero

tail /dev/zero sorgt hierbei, dass der Prozess immer mehr Daten bekommt, in wenigen Sekunden werden die gesetzten Grenzen erreich sein, anschließend können Sie mit folgendem Befehl sehen, was passiert ist:

journalctl -u php-fpm8.1 --no-pager

Speicherprobleme frühzeitig stoppen

OOM beginnt seine Arbeit erst im letzten Moment – also, bevor es wirklich kritisch wird. So kann es sein, dass das Betriebssystem ein paar Minuten sehr langsam ist, bevor OOM wirklich Prozesse killt.

OOM zieht seine Daten aus der Datei „/proc/pressure/memory„, also dem Speicherdruck des Systems, ob diese aktiv ist (bei Red Hat, Rocky und ähnlichen Systemen nicht), zeigt der Befehl:

cat /proc/pressure/memory

Erhalten Sie hier eine Ausgabe wie im Screenshot oben – aktiv. Ist die Funktion nicht aktiv, können Sie diese mit folgendem Befehl aktivieren:

grubby --update-kernel=ALL --args="psi=1"
reboot

Je nach System können auch entsprechende Pakete fehlen, die Sie wie folgt installieren und aktivieren:

apt install systemd-oomd 
systemctl enable --now systemd-oomd
dnf install systemd-oomd
systemctl enable --now systemd-oomd

Jetzt können wir OOM zeigen, wann es seine Arbeit beginnen soll, hierzu öffnen wir die die Systemd-Datei „slice“ und bearbeiten diese:

systemctl edit system.slice

Hier fügen wir folgende Konfiguration hinzu:

# /etc/systemd/system/system.slice.d/override.conf 
[Slice] 
ManagedOOMMemoryPressure=kill 
ManagedOOMMemoryPressureLimit=60%
  • ManagedOOMMemoryPressure=kill – weist Systemd-OOMD an, entsprechende Dienste zu überwachen und zu beenden, wenn der Speicherdruck zu hoch bleibt.
  • ManagedOOMMemoryPressureLimit=60% – legt den Schwellwert der Speicherauslastung fest. Wird der vorkonfigurierte Wert innerhalb der vorkonfigurierten Zeit (standardmäßig 30 Sekunden) – hier 60 Prozent überschritten, beginnt OOM seine Arbeit und wartet nicht bis zum letzten Moment. Die vorkonfigurierte Zeit legen Sie in der Datei „/etc/systemd/oomd.conf“ fest.

Mit dem Befehl oomctl können Sie anschließend die aktuellen Einstellungen anzeigen lassen.

Categories:

Tags:

Schreibe einen Kommentar

Noch keine Reaktion

Neue Themen im Forum
Sparsames System für betagtes Not …Hallo Andreas, willkommen auf der Linux-Bibel. Debian 13 mit X … Weiterlesen
Bottles startet nicht mehrHallo, das Datum ist kein Zufall. Am 23.10. kam eine neue Bottles … Weiterlesen
ltrace ... oder was macht ein Pro …Mit strace haben wir uns die Schnittstelle zum Kern angeschaut und … Weiterlesen
Kategorien im Wiki
WIKI-Beiträge des Monates

Die Beiträge des Monates finden Sie im Kalender unter den blau markierten Tageszahlen.

Oktober 2026
M D M D F S S
 1234
567891011
12131415161718
19202122232425
262728293031  
Archiv