PQ
PQ.Hosting

Валюта

OOM Killer убил процесс: как найти виновника и не допустить повторения

Автор
PQ
24 марта 2026
5 мин чтения
4 просмотров
OOM Killer убил процесс: как найти виновника и не допустить повторения

Сервер работал, процесс исчез. Без segfault, без явной ошибки в логах приложения. Если в системных журналах есть строка Out of memory: Kill process — это OOM Killer. Ядро Linux решило что памяти не хватает и выбрало жертву по своему алгоритму. Разбираем как найти что именно убили, почему выбрали именно этот процесс и как это предотвратить.

Шаг 1: подтвердить что виновник — OOM Killer

Смотреть в журнал ядра:

sudo journalctl -k | grep -i "oom\|kill" | tail -30

Или через dmesg с временными метками:

dmesg -T | grep -i "oom\|killed process" | tail -30

Типичный вывод:

[Mar 24 03:17:42] Out of memory: Kill process 14821 (php-fpm) score 847 or sacrifice child
[Mar 24 03:17:42] Killed process 14821 (php-fpm) total-vm:2048000kB, anon-rss:1843200kB, file-rss:4096kB, shmem-rss:0kB

Здесь: имя процесса php-fpm, PID 14821, score 847 — чем выше, тем вероятнее убийство, и размер занятой памяти в момент убийства.

Посмотреть все OOM-события за последние сутки:

sudo journalctl -k --since "24 hours ago" | grep "Out of memory"

Шаг 2: понять почему убили именно этот процесс

OOM Killer не убивает случайно. Каждый процесс получает oom_score от 0 до 1000 — чем выше, тем привлекательнее жертва. Алгоритм учитывает: размер занятой памяти, время жизни процесса (новые менее ценны), запущен ли как root, и oom_score_adj — ручная поправка.

Посмотреть текущий score любого процесса по PID:

cat /proc/$(pgrep nginx)/oom_score

Посмотреть поправку — oom_score_adj:

cat /proc/$(pgrep nginx)/oom_score_adj

Диапазон oom_score_adj: от -1000 (никогда не убивать) до +1000 (убить первым).

Топ процессов по oom_score прямо сейчас:

ps aux --sort=-%mem | head -10 | awk '{print $2}' | xargs -I{} sh -c 'echo -n "{} $(cat /proc/{}/comm 2>/dev/null): "; cat /proc/{}/oom_score 2>/dev/null' | sort -t: -k2 -rn | head -10

Шаг 3: посмотреть сколько памяти было в момент убийства

OOM Killer перед убийством печатает в dmesg полный снимок состояния памяти. Найти его:

dmesg -T | grep -A 30 "Out of memory" | head -50

В выводе будет таблица всех процессов с их RSS в момент события. Это позволяет понять кто реально съел всю память — не всегда это тот кого убили.

Как защитить конкретный процесс от убийства

Выставить oom_score_adj = -1000 — ядро никогда не убьёт этот процесс:

echo -1000 | sudo tee /proc/$(pgrep sshd)/oom_score_adj

Для systemd-сервисов — добавить в unit-файл:

sudo systemctl edit nginx
[Service]
OOMScoreAdjust=-900

Применить:

sudo systemctl daemon-reload
sudo systemctl restart nginx

Значение -900 — очень маловероятно убьют. -1000 — гарантированно не убьют (используйте только для критических сервисов вроде sshd).

Как сделать процесс более привлекательной жертвой

Например, фоновый воркер не критичен — пусть OOM Killer возьмёт его первым:

echo 500 | sudo tee /proc/$(pgrep worker)/oom_score_adj

Или в systemd unit:

[Service]
OOMScoreAdjust=500

Системные настройки: vm.overcommit_memory

По умолчанию Linux разрешает overcommit — процессы могут зарезервировать больше памяти чем физически есть, в расчёте что не используют всё сразу. Когда использование превышает реальный объём — приходит OOM Killer.

Посмотреть текущий режим:

cat /proc/sys/vm/overcommit_memory

Три режима:

  • 0 — эвристический overcommit (по умолчанию)
  • 1 — разрешить любой overcommit без ограничений
  • 2 — запретить overcommit; процессы получат ошибку при выделении если памяти нет

Режим 2 самый предсказуемый для продакшн-серверов. Процесс упадёт с ENOMEM при попытке выделить память а не будет убит внезапно.

Установить режим 2:

sudo sysctl -w vm.overcommit_memory=2

Сделать постоянным:

echo "vm.overcommit_memory=2" | sudo tee -a /etc/sysctl.d/99-memory.conf
sudo sysctl -p /etc/sysctl.d/99-memory.conf

При режиме 2 также настроить vm.overcommit_ratio — какой процент RAM+swap разрешён:

echo "vm.overcommit_ratio=80" | sudo tee -a /etc/sysctl.d/99-memory.conf

vm.swappiness: замедлить OOM через swap

Если swap есть но не используется — ядро держит данные в RAM и вызывает OOM раньше времени. Снизить порог переключения на swap:

cat /proc/sys/vm/swappiness

По умолчанию 60. На VPS где swap медленный — лучше 10–20:

sudo sysctl -w vm.swappiness=10
echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.d/99-memory.conf

Ограничить память через cgroup (не дать процессу убить сервер)

Вместо того чтобы ждать OOM — ограничить сколько памяти может занять конкретный сервис. Тогда OOM Killer убьёт только воркеры этого сервиса, не трогая остальные.

Для systemd-сервиса:

sudo systemctl edit php8.1-fpm
[Service]
MemoryMax=512M
MemorySwapMax=0

MemoryMax — жёсткий лимит RAM. MemorySwapMax=0 — запретить использовать swap. При превышении лимита cgroup триггерит локальный OOM внутри группы и убивает только процессы этого сервиса.

Посмотреть текущее потребление памяти по сервисам:

systemd-cgtop -m

Мониторинг: получить алерт до того как рванёт

Скрипт который отправляет предупреждение когда доступная память падает ниже порога:

#!/bin/bash
THRESHOLD=10
AVAILABLE=$(free | awk '/^Mem:/ {printf "%.0f", $7/$2*100}')
if [ "$AVAILABLE" -lt "$THRESHOLD" ]; then
    echo "WARNING: only ${AVAILABLE}% RAM available on $(hostname)" | \
    mail -s "Low memory alert" admin@example.com
fi

Добавить в cron каждые 5 минут:

*/5 * * * * /usr/local/bin/memory-check.sh

Шпаргалка

Задача Команда
Найти OOM-события sudo journalctl -k | grep "Out of memory"
OOM через dmesg dmesg -T | grep -i "oom|killed process"
oom_score процесса cat /proc/PID/oom_score
Защитить процесс от убийства echo -1000 | sudo tee /proc/PID/oom_score_adj
Защита через systemd OOMScoreAdjust=-900 в unit-файле
Режим overcommit cat /proc/sys/vm/overcommit_memory
Запретить overcommit sysctl -w vm.overcommit_memory=2
Ограничить RAM сервиса MemoryMax=512M в systemd unit
Мониторинг по сервисам systemd-cgtop -m
Текущий swappiness cat /proc/sys/vm/swappiness

 

Поделиться статьей

Похожие статьи