Linux OOMВысокая

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

Статья объясняет механизм OOM Killer (Out-Of-Memory Killer) в ядре Linux, приводит конкретные причины его срабатывания и даёт практические способы диагностики и устранения проблемы — от анализа логов до настройки параметров ядра и оптимизации приложений.

Обновлено 15 февраля 2026 г.
15-30 мин
Средняя
FixPedia Team
Применимо к:Ubuntu 20.04+RHEL 8+Ядро Linux 5.x+Docker 20.10+

Что означает ошибка OOM Killer

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

Типичное сообщение в логах (dmesg или journalctl -k):

[12345.678] Out of memory: Kill process 1234 (python3) score 500 or sacrifice child
[12345.679] Killed process 1234 (python3) total-vm:204800kB, anon-rss:150000kB, file-rss:0kB

Симптомы для пользователя:

  • Неожиданное завершение приложений или служб.
  • Сообщения вроде Killed в консоли при запуске команд.
  • Резкий рост использования swap (видно в free -h).
  • Система становится неотзывчивой, затем "оживает" после убийства процесса.

Причины возникновения

  1. Физическая нехватка RAM + swap. Запущено слишком много тяжелых приложений (виртуальные машины, базы данных, компиляция), которые в сумме требуют больше памяти, чем доступно.
  2. Утечки памяти в приложениях. Программа (например, на Python, Java, Node.js) постепенно потребляет всё больше RAM, не освобождая неиспользуемые объекты.
  3. Недостаточный swap-раздел или swap-файл. На системах с малым объёмом RAM (например, Raspberry Pi или облачные инстансы) swap может быть слишком мал или отсутствовать.
  4. Неправильные настройки overcommit. Параметр vm.overcommit_memory=0 (по умолчанию) позволяет процессам запрашивать больше памяти, чем есть физически, что может привести к внезапному исчерпанию.
  5. Контейнеры Docker без лимитов. Контейнеры по умолчанию могут использовать всю память хоста. Если один контейнер "съедает" всё, OOM Killer убьёт процессы в других контейнерах или на хосте.
  6. Фоновые службы с утечками. Долгоживущие демоны (например, веб-серверы, агенты мониторинга) могут накапливать данные в памяти без очистки.

Способы решения

Способ 1: Анализ логов и идентификация "потребителя"

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

  1. Найдите запись в логах ядра:
    dmesg -T | grep -i "killed process"
    # или
    journalctl -k --since "1 hour ago" | grep -i oom
    

    В выводе будет PID и имя процесса (например, python3, java, mysqld).
  2. Проверьте, какие процессы сейчас используют больше всего памяти:
    # Сортировка по использованию RAM (в %)
    top -b -n 1 | sort -k10 -rn | head -20
    # Или более наглядный htop (если установлен)
    htop
    
  3. Если процесс уже завершён, посмотрите историю его потребления (если есть мониторинг) или логи приложения на предмет утечек.

💡 Совет: Для долгосрочного мониторинга настройте Grafana + Prometheus или используйте утилиты вроде netdata, чтобы видеть графики использования памяти.

Способ 2: Временное увеличение swap-пространства

Если у вас мало swap, это первая и быстрая мера (особенно на VPS или Raspberry Pi).

  1. Проверьте текущий swap:
    free -h
    swapon --show
    
  2. Создайте swap-файл (например, 4 ГБ):
    sudo fallocate -l 4G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    
  3. Сделайте его постоянным (добавьте в /etc/fstab):
    echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
    
  4. Настройте vm.swappiness (опционально). Значение 10-30 рекомендуется для серверов:
    sudo sysctl vm.swappiness=10
    echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
    

Способ 3: Настройка параметров overcommit

Ядро Linux по умолчанию (vm.overcommit_memory=0) разрешает процессам запрашивать больше памяти, чем есть физически + swap. Это может привести к ситуации, когда OOM Killer сработает резко.

  1. Установите строгий режим (vm.overcommit_memory=2), который запрещает overcommit сверх лимита:
    sudo sysctl vm.overcommit_memory=2
    
  2. Установите процент доступной памяти для overcommit (vm.overcommit_ratio). Например, 80% от суммы RAM + swap:
    # Предположим, RAM=4G, swap=4G, всего 8G. 80% = 6.4G
    sudo sysctl vm.overcommit_ratio=80
    
  3. Сделайте настройки постоянными:
    echo 'vm.overcommit_memory=2' | sudo tee -a /etc/sysctl.conf
    echo 'vm.overcommit_ratio=80' | sudo tee -a /etc/sysctl.conf
    

⚠️ Важно: Слишком низкий overcommit_ratio может привести к ошибкам Cannot allocate memory у приложений, которые запрашивают память, но не используют её сразу (например, JVM). Тестируйте в staging-среде.

Способ 4: Оптимизация конкретных приложений

Для Java-приложений (Tomcat, Spring Boot, Kafka)

Уменьшите максимальный размер кучи (-Xmx). Например, вместо -Xmx4g поставьте -Xmx2g, если процессу хватает.

# Пример systemd-юнита для Java-сервиса
[Service]
Environment="JAVA_OPTS=-Xmx2g -XX:+UseG1GC"
ExecStart=/usr/bin/java $JAVA_OPTS -jar app.jar

Для Python-приложений (Django, Flask)

  • Используйте менеджеры процессов (Gunicorn, uWSGI) с ограничением рабочих процессов.
  • Проверьте утечки через tracemalloc или objgraph.
  • Для long-running задач (Celery) настройте лимиты памяти в конфиге.

Для Node.js

Установите лимит через --max-old-space-size:

node --max-old-space-size=2048 server.js  # 2 ГБ кучи

Способ 5: Настройка Docker-контейнеров

Если OOM Killer убивает процессы в контейнерах, нужно установить лимиты памяти для каждого контейнера.

  1. Запустите контейнер с явными лимитами:
    docker run -d \
      --name myapp \
      --memory=2g \
      --memory-swap=3g \  # swap = memory-swap - memory
      myimage:latest
    
  2. Для docker-compose:
    services:
      app:
        image: myapp:latest
        deploy:
          resources:
            limits:
              memory: 2G
              memory-swap: 3G
    
  3. Проверьте лимиты запущенных контейнеров:
    docker stats
    

Способ 6: Защита критичных процессов через oom_score_adj

OOM Killer вычисляет "оценку" (score) для каждого процесса (0-1000). Чем выше оценка, тем вероятнее убийство. Можно вручную понизить оценку для важных служб.

  1. Для уже запущенного процесса:
    # Установить минимальный score (требуются права root)
    echo -1000 | sudo tee /proc/<PID>/oom_score_adj
    
  2. Для systemd-службы (рекомендуется). Создайте дроп-ин в /etc/systemd/system/<service>.d/oom.conf:
    [Service]
    OOMScoreAdjust=-900
    

    Затем перезапустите службу: sudo systemctl daemon-reload && sudo systemctl restart <service>.

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

  1. Регулярный мониторинг. Настройте алерты (через Prometheus Alertmanager, Zabbix) на пороги использования памяти (например, 80% RAM + 70% swap).
  2. Аудит приложений на утечки. Для Java — jcmd <PID> GC.heap_info, для Python — pip install memray и профилирование.
  3. Прогрессивное выделение swap. На серверах с большим RAM (>32 ГБ) swap может быть небольшим (4-8 ГБ), но он должен быть. На встраиваемых системах (Raspberry Pi) — 1-2 ГБ swap обязательны.
  4. Избегайте overcommit в production. Установите vm.overcommit_memory=2 и vm.overcommit_ratio=80 на всех продакшн-серверах.
  5. Лимитирование контейнеров. Всегда указывайте --memory и --memory-swap для Docker-контейнеров в продакшене.
  6. Тестирование нагрузкой. Используйте stress-ng или memtester для проверки поведения системы при высокой нагрузке на память:
    stress-ng --vm 2 --vm-bytes 2G --timeout 60s
    

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

Чем OOM Killer отличается от использования swap-раздела?
Как найти, какой именно процесс был убит OOM Killer?
Можно ли полностью отключить OOM Killer?
Как защитить важный процесс от убийства OOM Killer?

Полезное

Анализ использования памяти
Проверка логов ядра на наличие OOM
Временное увеличение swap-пространства
Настройка параметров виртуальной памяти
Оптимизация или лимитирование приложений
Настройка OOM score для критичных процессов