Linux & Administration

OOM killer

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

Что такое OOM killer

OOM killer (Out Of Memory killer) — часть ядра Linux, включающаяся, когда в системе кончилась оперативная память и её негде взять. Ядро выбирает процесс, отправляет ему SIGKILL и освобождает память. Выбор не обсуждается: SIGKILL не перехватывается, процесс умирает мгновенно, без сохранения данных и корректного завершения.

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

Типичный симптом: приложение исчезло без записи в собственном логе. В логе приложения — тишина, потому что ему не дали и слова сказать. Причину ищут в ядре.

Как понять, что это был он

sudo dmesg -T | grep -i -E "out of memory|killed process"
sudo journalctl -k --since "1 hour ago" | grep -i "killed process"

Строка выглядит так:

Out of memory: Killed process 2847 (gunicorn) total-vm:2891234kB,
anon-rss:1948120kB, file-rss:0kB, shmem-rss:0kB, UID:1001 oom_score_adj:0

Здесь anon-rss — сколько процесс реально занимал на момент казни. Это отправная точка расследования.

В Docker и Kubernetes свой почерк — код выхода 137 (128 + 9, где 9 = SIGKILL) и статус OOMKilled: docker inspect --format '{{.State.OOMKilled}}' mycontainer. Важно, что в контейнере OOM срабатывает не только от нехватки памяти на хосте, но и от превышения лимита самого контейнера (--memory, resources.limits.memory). Хост при этом свободен, а под всё равно перезапускается по кругу.

Кого он выберет

Ядро считает каждому процессу oom_score — грубо говоря, чем больше памяти занимает процесс, тем он вероятнее жертва. Скорректировать можно через oom_score_adj (от −1000 до 1000):

cat /proc/<PID>/oom_score          # текущая оценка
echo -500 > /proc/<PID>/oom_score_adj    # защитить процесс

Значение −1000 полностью выводит процесс из-под удара. Для службы под systemd то же самое задаётся в юните:

[Service]
OOMScoreAdjust=-500
MemoryMax=2G

Ирония в том, что жертвой обычно становится главный сервис машины — PostgreSQL или Gunicorn занимают больше всех памяти именно потому, что они здесь главные.

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

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

Отсюда парадокс: malloc() успешно вернул адрес, а процесс убит при попытке в него записать.

Второй источник путаницы — вывод free -h. Колонка free почти всегда близка к нулю, и это нормально: Linux отдаёт свободную память под дисковый кеш и вернёт её приложению по первому требованию. Реальный запас смотрите в колонке available.

Как не доводить до этого

  • Ограничивайте сервисы явноMemoryMax в systemd или --memory в Docker: пусть падает один виновник, а не случайный сосед
  • Считайте воркеры — 9 воркеров Gunicorn по 300 МБ это 2.7 ГБ, а не «немного»
  • Добавьте swap на VPS — пара гигабайт файла подкачки не заменит память, но даст время среагировать вместо мгновенной смерти
  • МониторьтеPrometheus или Zabbix с алертом на available ниже 15%
  • Restart=always — не лечит причину, но поднимает сервис за секунды

Это не то же самое, что CUDA out of memory

Частая путаница у тех, кто работает с ML. CUDA out of memory — нехватка VRAM на видеокарте, и обрабатывает её драйвер GPU: PyTorch выбрасывает исключение, процесс остаётся жив и вы видите traceback. OOM killer же работает только с обычной RAM и убивает процесс целиком без объяснений. Симптомы разные: traceback про CUDA — тюньте batch size и квантизацию, молчаливая смерть процесса — смотрите dmesg.

Связанные термины

  • Linux — ядро, где живёт этот механизм
  • systemd / демоны — лимиты памяти и автоперезапуск сервисов
  • Gunicorn / WSGI — частая жертва из-за числа воркеров
  • Docker — где OOM превращается в код 137
  • VPS — среда, где память кончается чаще всего
  • VRAM — память GPU, с которой OOM killer не связан

Готовы запустить GPU-задачу?

Запустить GPU-сервер