OOM Killer (Out of Memory Killer) — механизм ядра Linux, который при исчерпании физической RAM и свопа принудительно завершает процессы, чтобы предотвратить полный крах системы. Активируется автоматически и действует за доли секунды — отключить его штатными средствами нельзя, но можно управлять приоритетами выбора жертв.
Как OOM Killer выбирает жертву
Ядро вычисляет для каждого процесса «оценку плохости» (badness score) от 0 до 1000. Чем выше оценка — тем больше вероятность, что процесс будет убит. Формула учитывает:
- Размер виртуальной памяти процесса и всех его потоков.
- Время работы: долгоживущие процессы получают скидку.
- Запущен ли процесс от root (небольшая скидка).
- Значение
oom_score_adj— ручная корректировка от -1000 до +1000.
Процесс с наибольшим badness score получает SIGKILL и немедленно завершается. Его память освобождается для остальных процессов.
Управление через oom_score_adj
Каждый процесс имеет файл /proc/[PID]/oom_score_adj. Допустимые значения:
- -1000 — процесс никогда не будет убит OOM Killer (oom_score_adj_min). Используй для системных демонов: sshd, базы данных.
- 0 — стандартное значение, без корректировки.
- +1000 — первый кандидат на уничтожение. Удобно для процессов, потеря которых некритична.
# Защитить процесс nginx от OOM Killer:
echo -1000 > /proc/$(pgrep nginx | head -1)/oom_score_adj
# Сделать процесс приоритетной жертвой:
echo 1000 > /proc/$(pgrep test-app)/oom_score_adj
В systemd-сервисах параметр задаётся через директиву OOMScoreAdjust в unit-файле — изменение сохраняется при перезапуске.
История
OOM Killer появился в ядре Linux в начале 1990-х как решение проблемы memory overcommit — оптимистичного выделения памяти, когда сумма запрошенной памяти превышает физическую RAM + swap. Ядро рассчитывает, что не все процессы используют всё выделенное одновременно. Алгоритм неоднократно переписывался — современная версия на основе badness score появилась в версии ядра 2.6.36 (2010).
OOM на VPS и контейнерах
На VPS и VDS ситуация усложняется: провайдер может использовать overcommit на уровне гипервизора. При OpenVZ-виртуализации лимиты памяти жёсткие — превышение вызывает OOM немедленно. При KVM — поведение стандартное Linux. В Docker-контейнерах лимит задаётся флагом --memory; при превышении Docker сам посылает SIGKILL без участия системного OOM Killer.
Предотвращение OOM в продакшне
Правильное планирование памяти: сумма requests.memory всех контейнеров/процессов не должна превышать доступную RAM. Добавить swap на VPS: 1-2 ГБ swap снижает риск OOM при кратковременных пиках, но не заменяет увеличение RAM. Инструменты анализа: ps aux --sort=-%mem (топ по памяти), pmap -x
Настройка vm.overcommit_memory: 0 (default) — ядро разрешает overcommit с эвристикой, 1 — всегда разрешать (опасно), 2 — никогда (строгий режим). Для production-серверов с предсказуемой нагрузкой vm.overcommit_memory=2 + vm.overcommit_ratio=80 предотвращает OOM за счёт отказа в выделении памяти сверх 80% физической RAM. Проверка: /proc/sys/vm/overcommit_memory, применить через sysctl -w или /etc/sysctl.conf.
Как диагностировать OOM Killer
Записи OOM Killer в системном журнале:
# Поиск в dmesg:
dmesg | grep -i "oom"
# Поиск в journald:
journalctl -k | grep -i "oom\|killed process"
Запись выглядит примерно так: Out of memory: Kill process 12345 (nginx) score 892 or sacrifice child. После неё — список всех процессов с их oom_score на момент события. Если OOM срабатывает регулярно — решение не в настройке oom_score_adj, а в добавлении RAM, включении свопа или устранении утечек памяти в приложении.