Лимиты памяти на Linux-сервере: практический чек-лист
Процесс может упереться в лимит памяти, хотя на сервере ещё есть свободные гигабайты. Проверьте, кто выставил ограничение — cgroup, systemd или Docker, — и найдите признаки OOM до того, как сервис начнёт перезапускаться.

Сервис на Linux может получить отказ по памяти, даже если команда free показывает свободное место: ограничение часто задано не всему серверу, а конкретному процессу, службе или контейнеру. Этот чек-лист поможет найти источник лимита и понять, что произошло. Примеры рассчитаны на Linux с cgroup v2; конкретные названия и доступность параметров systemd и Docker зависят от установленных версий.
Сначала определите масштаб проблемы
Не начинайте с увеличения лимита. Сначала выясните, ограничена ли вся машина или только отдельная нагрузка. Для первичной проверки выполните:
free -h
cat /proc/meminfo
ps -eo pid,comm,rss --sort=-rss | head
free показывает общую картину, а список процессов — тех, у кого сейчас больше всего резидентной памяти. Это снимок текущего состояния: он не докажет, сколько памяти процесс потреблял в момент сбоя. Поле available в выводе free обычно полезнее для оценки доступной памяти, чем free само по себе: Linux использует часть свободной памяти для кэша.
Проверьте и ошибки ядра вокруг времени сбоя:
sudo journalctl -k --since "1 hour ago" | grep -Ei 'out of memory|oom|killed process'
Если нашли сообщение об OOM, запишите имя процесса, время и, если присутствует, его PID. Но отсутствие совпадения в этой выборке ещё не доказывает, что лимита не было: журнал мог быть очищен, а ограничение могло сработать внутри cgroup без понятного сообщения в выбранном диапазоне.
Проверьте ограничения cgroup
cgroup1 — механизм Linux, который учитывает и ограничивает ресурсы групп процессов. На системе с cgroup v2 файлы контроллера памяти обычно доступны в иерархии /sys/fs/cgroup. Сначала убедитесь, что используется единая иерархия:
stat -fc %T /sys/fs/cgroup
Результат cgroup2fs указывает на cgroup v2. Для конкретного процесса найдите его путь:
cat /proc/PID/cgroup
Замените PID на числовой идентификатор процесса. В cgroup v2 строка обычно содержит путь после 0::. Сопоставьте его с деревом /sys/fs/cgroup и проверьте в соответствующем каталоге файлы:
cat /sys/fs/cgroup/PATH/memory.current
cat /sys/fs/cgroup/PATH/memory.max
cat /sys/fs/cgroup/PATH/memory.events
Замените PATH путём из записи процесса. Если процесс находится в корневой cgroup, путь будет короче. memory.current показывает текущее потребление группы, memory.max — установленный верхний предел; значение max означает, что явный лимит в этой группе не задан. Проверьте также родительские каталоги: ограничение выше по дереву может действовать на процесс, даже если в его собственной cgroup стоит max.
В memory.events ищите ненулевые счётчики max, oom и oom_kill. Они помогают отличить достигнутый предел от простого высокого потребления. Счётчики накапливаются, пока живёт cgroup: смотрите не только на число, но и на его изменение до и после воспроизведения проблемы.
Найдите, кто установил лимит
Одни и те же cgroup-файлы могут обслуживать разные уровни управления. Проверьте источник ограничения, прежде чем менять настройки.
| Где запущена нагрузка | Что проверить | Цена изменения |
|---|---|---|
| Служба systemd | Параметры службы и её cgroup | Лимит меняется для службы; нужно оценить влияние на соседние нагрузки и перезапуск |
| Контейнер Docker | Ограничение контейнера и его состояние | Увеличение лимита требует ресурсов хоста; контейнер может быть пересоздан при изменении конфигурации |
| Процесс без явного лимита | Родительские cgroup, журналы ядра, давление на память хоста | Изменение лимитов не устранит утечку и может приблизить отказ всей машины |
Для службы systemd
Уточните свойства службы командой:
systemctl show SERVICE -p MemoryCurrent -p MemoryMax -p MemoryHigh
Замените SERVICE именем юнита, например my-app.service. Пустое или неограниченное значение не исключает ограничения в родительской cgroup. Сверьте результат с файлами cgroup и конфигурацией юнита. Не меняйте лимит вслепую: сначала оцените фактический максимум потребления и запас памяти, который нужен ОС и другим службам.
Для Docker
Проверьте параметры контейнера и не ограничен ли он при запуске:
docker inspect CONTAINER --format '{{.HostConfig.Memory}} {{.State.OOMKilled}}'
docker stats --no-stream CONTAINER
Замените CONTAINER именем или идентификатором. В первой команде выводится настроенный лимит в байтах и признак, сообщил ли Docker об OOM для текущего состояния контейнера; во второй — текущая статистика. Нулевой лимит в поле конфигурации означает отсутствие заданного здесь предела, но не исключает ограничения родительской cgroup или нехватки памяти на хосте. Смотрите также конфигурацию оркестратора, если контейнером управляет не сам Docker CLI.
Свободная память на хосте не отменяет лимит cgroup. И наоборот: отсутствие лимита у процесса не защищает его от OOM на машине, где память закончилась целиком.
Чек-лист перед изменением лимита
- Зафиксируйте время сбоя, PID или имя контейнера и сообщения приложения. Проверка: для инцидента есть временная точка, с которой можно сопоставить журналы.
- Проверьте
free -hи сообщения ядра. Проверка: понятно, есть ли признаки нехватки памяти на хосте или OOM. - Найдите cgroup процесса через
/proc/PID/cgroup, затем прочитайтеmemory.current,memory.maxиmemory.eventsв его каталоге и родительских каталогах. Проверка: известны применимый предел и счётчики событий. - Сопоставьте cgroup с systemd, Docker или другим менеджером. Проверка: найдено место, где задаётся лимит, а не только файл, в котором он проявляется.
- Снимите потребление повторно во время нагрузки и после неё; зафиксируйте время и условия. Проверка: видно, растёт ли использование постепенно, достигает ли плато и увеличиваются ли OOM-счётчики.
- Только после этого меняйте настройку или оптимизируйте приложение. Проверка: повторный тест проходит без роста ошибок, а память хоста остаётся с запасом.
Когда повышение лимита не поможет
Если потребление растёт со временем при стабильной нагрузке, вероятна утечка или неограниченное накопление данных. Больше памяти отодвинет сбой, но не исправит причину. Если OOM-счётчики не растут, а процесс завершает работу, изучите журнал приложения: причина может быть не в лимите памяти.
Осторожно и с механическим переносом значений между окружениями. Лимит контейнера, предел службы и доступная память хоста — разные уровни. Если поднять ограничение нескольких контейнеров одновременно, их суммарный возможный расход может превысить память машины. Для подтверждения соберите временной ряд потребления на характерной нагрузке, а не опирайтесь на один снимок.
Что делать дальше
Сохраните исходные значения лимита и счётчиков, затем повторите нагрузку с мониторингом. Для приложения полезно отдельно измерять потребление процесса и число перезапусков; для cgroup — текущую память и динамику memory.events. Если проблема повторяется, связывайте графики, журналы приложения и события ядра по времени. Проверки памяти не заменяют анализ утечек, настройку кешей и оценку потребления дочерними процессами.
1. cgroup — группа процессов Linux, для которой ядро может учитывать и ограничивать ресурсы, в том числе память.
Тендерный специалист 44-ФЗ / 223-ФЗ: Разбор PDF-документации закупки, поиск «заточек» под поставщика, чек-лист заявки.
Спросить за 20 ₽Источники: Linux kernel documentation: cgroup v2, Docker Docs: Resource constraints
Частые вопросы
Почему сервис падает, если на сервере ещё есть свободная память?
Что означает `max` в файле `memory.max`?
Можно ли просто увеличить лимит памяти?
Что делать, если в журнале ядра нет сообщения об OOM?
Можно ли применять команды из статьи на cgroup v1?
Почему `docker stats` показывает нормальное потребление, а контейнер завершился?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.