LinuxВысокая

OOM Killer в Linux: как обнаружить и предотвратить

Этот гайд объясняет механизм OOM Killer в Linux и предоставляет практические шаги по диагностике и предотвращению завершения процессов из-за нехватки памяти. Вы научитесь анализировать логи, настраивать приоритеты процессов и управлять памятью с помощью cgroups.

Обновлено 14 февраля 2026 г.
15-30 мин
Средняя
FixPedia Team
Применимо к:Ubuntu 20.04+CentOS 7+Debian 11+ядро Linux 4.15+

Что такое OOM Killer и почему он появляется

OOM Killer (Out-of-Memory Killer) — это механизм ядра Linux, который автоматически завершает процессы, когда система исчерпала доступную оперативную память (RAM) и swap-пространство. Его цель — освободить память, чтобы ядро и критические системные процессы могли продолжить работу, предотвращая полный крах системы.

Обычно OOM Killer активируется, когда:

  • Физическая RAM и swap заполнены на 100%.
  • Приложение имеет утечку памяти (memory leak).
  • На сервере запущено слишком много memory-intensive процессов.
  • Неправильно настроены лимиты памяти в контейнерах (Docker/Kubernetes).

Если вы видите в логах сообщение Killed process или приложение внезапно завершается с кодом 137 (SIGKILL), скорее всего, виноват OOM Killer.

Как работает OOM Killer

Ядро Linux вычисляет oom_score для каждого процесса на основе:

  • Доли памяти, потребляемой процессом (основной фактор).
  • Привилегий процесса (процессы root имеют меньший шанс быть убитыми).
  • Времени жизни процесса (долгоживущие процессы могут иметь более высокий score).

Процесс с самым высоким oom_score выбирается для завершения. Однако это не всегда оптимально: OOM Killer может убить важный сервис, а оставить фоновый процесс с утечкой.

Диагностика проблемы

Перед любыми действиями нужно подтвердить, что проблема именно в OOM Killer.

  1. Проверьте логи ядра:
    dmesg | grep -i kill
    

    Пример вывода:
    [12345.678] Out of memory: Kill process 1234 (nginx) score 500 or sacrifice child
    [12345.680] Killed process 1234 (nginx) total-vm:1234567kB, anon-rss:456789kB, file-rss:0kB
    

    Здесь видно, что процесс nginx с PID 1234 был убит.
  2. Оцените общую память:
    free -h
    

    Обратите внимание на столбцы total, used, available и Swap. Если available близок к нулю, а Swap также заполнен — система в критическом состоянии.
  3. Найдите процесс-потребителя:
    top -b -n 1 | head -20
    

    Или используйте htop с сортировкой по памяти (клавиша F6MEM%).
  4. Проверьте oom_score процессов:
    for pid in $(ps -e | awk '{print $1}' | tail -n +2); do
      echo "PID $pid: $(cat /proc/$pid/oom_score 2>/dev/null) (adj: $(cat /proc/$pid/oom_score_adj 2>/dev/null))"
    done | sort -k3 -n -r | head -10
    

    Это покажет топ-10 процессов с наивысшим oom_score.

Методы решения проблемы

Шаг 1: Настройка oom_score_adj для защиты ключевых процессов

Каждому процессу можно задать adj-значение от -1000 (максимальная защита) до +1000 (максимальный приоритет на убийство). Это самый быстрый способ защитить процесс.

Для одноразовой настройки (до перезагрузки):

# Замените <PID> на идентификатор процесса
echo -1000 > /proc/<PID>/oom_score_adj

Для постоянной настройки через systemd (рекомендуется): Создайте или отредактируйте юнит:

# /etc/systemd/system/ваш-сервис.service.d/oom-protect.conf
[Service]
OOMScoreAdjust=-1000

Затем перезапустите сервис: systemctl daemon-reload && systemctl restart ваш-сервис.

Важно: Не устанавливайте oom_score_adj=-1000 для всех процессов — это может привести к тому, что OOM Killer не сможет освободить память и система зависнет.

Шаг 2: Использование cgroups для ограничения памяти

cgroups (control groups) позволяют задать жёсткие лимиты памяти для группы процессов. Это лучший способ для контейнеров и изолированных сервисов.

Через systemd (современные дистрибутивы):

# Запустить команду с лимитом 500 МБ
systemd-run --scope -p MemoryMax=500M /путь/к/команде

# Или для существующего сервиса создайте дроп-ин:
# /etc/systemd/system/ваш-сервис.service.d/limits.conf
[Service]
MemoryMax=1G
MemorySwapMax=2G  # если нужен swap

Вручную через cgroup v2:

# Создайте cgroup
sudo mkdir /sys/fs/cgroup/mylimit
# Установите лимит 1 ГБ
echo $((1*1024*1024*1024)) | sudo tee /sys/fs/cgroup/mylimit/memory.max
# Запустите процесс в этой группе
sudo echo $$ > /sys/fs/cgroup/mylimit/cgroup.procs && /путь/к/вашему/приложению

Шаг 3: Настройка параметров ядра

Изменение поведения OOM Killer на уровне ядра.

Вариант A: Запретить переcommit памяти (строгий контроль): В /etc/sysctl.conf добавьте:

vm.overcommit_memory = 2
vm.overcommit_ratio = 100  # разрешить commit только до 100% RAM+swap

Примените: sudo sysctl -p. Это предотвратит выделение памяти, которой физически нет, но может вызвать ошибки fork: Cannot allocate memory у приложений.

Вариант B: Режим паники вместо убийства (для отладки):

vm.panic_on_oom = 2

При нехватке памяти система упадёт в kernel panic, что полезно для сбора дампов, но неприемлемо для продакшена.

Вариант C: Изменить степень агрессивности OOM Killer (редко используется):

vm.oom_kill_allocating_task = 1  # убивать процесс, который выделил память, а не случайный

Шаг 4: Оптимизация приложения или увеличение ресурсов

Если проблема вызвана утечкой памяти:

  • Используйте профилировщики: valgrind --leak-check=full, heaptrack, perf.
  • Для Java-приложений: настройте -Xmx и -Xms в JVM.
  • Для Python: проверьте на утечки (например, через tracemalloc).

Если нагрузка обоснована:

  • Увеличьте объём RAM на сервере.
  • Добавьте swap-файл (временное решение, но не панацея):
    sudo fallocate -l 4G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    

Профилактика OOM Killer

  1. Мониторинг памяти:
    • Используйте Prometheus + node_exporter или Zabbix.
    • Настройте алерты при использовании RAM > 80%.
    • Пример команды для быстрой проверки: awk '/MemAvailable/ {print $2/1024" GB available"}' /proc/meminfo.
  2. Логирование использования памяти:
    # Запись каждые 5 минут в cron
    */5 * * * * /usr/bin/free -h >> /var/log/memory.log
    
  3. Регулярный аудит процессов:
    • Ищите процессы с аномально высоким oom_score.
    • Проверяйте контейнеры на соответствие лимитам.

Особенности в контейнерах (Docker/Kubernetes)

В контейнерах OOM Killer работает внутри изоляции cgroups, но если контейнер исчерпает свой лимит, ядро убьёт процесс внутри него.

Docker:

# Запуск с лимитом 512 МБ RAM и 1 ГБ swap
docker run -d --memory=512m --memory-swap=1g ваш-образ

# Проверка лимитов
docker stats

Kubernetes:

resources:
  limits:
    memory: "512Mi"
    cpu: "500m"
  requests:
    memory: "256Mi"

Убедитесь, что requests и limits установлены адекватно. При превышении лимита поды будет убит (OOMKilled).

Частые ошибки при настройке

  • Защита всех процессов через oom_score_adj=-1000: Это отключает OOM Killer полностью, что может привести к полной блокировке системы при нехватке памяти.
  • Установка слишком высоких лимитов cgroups: Если лимит выше, чем физическая RAM, OOM Killer всё равно сработает на уровне хоста.
  • Игнорирование swap: Swap замедляет систему, но может дать время на реакцию. Полный отказ от swap (swapoff -a) ускорит срабатывание OOM Killer.
  • Неправильное толкование логов: Сообщение Killed process может быть и от ручного kill -9. Всегда проверяйте dmesg и код выхода процесса (137 = SIGKILL, часто от OOM).

Что дальше?

После применения мер проверьте:

  1. Стабильность работы под нагрузкой (тесты с stress-ng или реальной нагрузкой).
  2. Логи на отсутствие новых записей OOM Killer.
  3. Корректность работы защищённых процессов (не потребляют ли они слишком много памяти в ущерб другим).

Если проблема остаётся, рассмотрите архитектурные изменения: шардирование, кэширование, использование более эффективных алгоритмов обработки данных.

Запомните: OOM Killer — это последний рубеж защиты системы. Лучшая стратегия — не допускать ситуаций, когда он срабатывает, через мониторинг и грамотное планирование ресурсов.

Часто задаваемые вопросы

Почему OOM Killer убивает важные системные процессы?
Как временно отключить OOM Killer?
Как защитить конкретный процесс от OOM Killer?
OOM Killer работает внутри Docker-контейнеров?

Полезное

Анализ логов ядра на наличие записей OOM Killer
Проверка текущего использования памяти
Настройка oom_score_adj для защиты процесса
Использование cgroups для ограничения памяти
Настройка параметров ядра
Оптимизация приложения или увеличение RAM