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-сервер