Когда срабатывает
Linux обычно переподписывается на память (overcommit) - если все процессы попросят одновременно всю свою заявленную память, физических страниц не хватит. Пока никто не пытается активно использовать - работает. Когда упёрлись:
- на хосте: kernel запускает global OOM killer
- в контейнере / cgroup'е с
memory.max: запускается cgroup OOM, убивает только в пределах этого cgroup'а
Альтернатива - общий kernel panic, но это последнее средство.
Как выбирается жертва
Каждому процессу присваивается oom_score (0..1000) на основе:
- сколько RAM он съел (главный фактор)
oom_score_adj- ручная корректировка (-1000 = неуязвим, +1000 = убьёт первым)- root-процессы получают небольшой штраф (минус несколько процентов)
Файлы:
cat /proc/<pid>/oom_score # текущий итоговый скор
cat /proc/<pid>/oom_score_adj # ручная корректировка
Как защитить критический процесс
echo -1000 | sudo tee /proc/$(pidof sshd)/oom_score_adj
▸теперь sshd никогда не будет жертвой OOM
В systemd-юните то же самое через OOMScoreAdjust=-1000.
OOM в cgroups v2
В v2 опция memory.oom.group = 1 меняет поведение: при OOM убивает не один
«худший» процесс, а весь cgroup. Это критично для приложений где
потеря одного worker'а ломает остальных (Kubernetes use case).
Признаки что был OOM
dmesg | grep -i 'killed process'
journalctl -k | grep -i oom
# Mar 14 12:34:56 host kernel: Out of memory: Killed process 1234 (chrome) ...
В контейнере docker inspect покажет:
docker inspect <container> --format '{{.State.OOMKilled}}'# true → контейнер был убит OOM, не сам завершился
Главные причины OOM на проде:
- Memory leak в приложении (Java/Node без heap-limit ровно до RAM сервера)
- Слишком тесный лимит в k8s - приложение работает но не помещается в лимит на пиках; решает увеличение request/limit или vertical autoscaling
- Большой ALLOCATION одной операцией (читать огромный файл целиком)