Самый частый вопрос про память в Linux: «free показывает 200 МБ свободно, это проблема?». Обычно нет. Linux старается использовать всю память, а важно, сколько её доступно.
free и available
free -m
total used free shared buff/cache available
Mem: 7940 5200 210 120 2530 2400
Swap: 2047 100 1947
free: память, не занятая ничем. Маленькое значение это норма.buff/cache: page cache (содержимое файлов) и буферы. Ядро отдаст большую часть этой памяти приложениям по первому требованию.available: оценка ядра, сколько можно выделить новым процессам без свопа. Смотреть надо на неё.
Источник всех этих чисел: /proc/meminfo (MemTotal, MemFree, MemAvailable, Cached, Dirty, SwapTotal и другие).
Page cache
Когда процесс читает файл, ядро оставляет его страницы в памяти: следующее чтение пойдёт из RAM. Запись тоже сначала попадает в кеш как «грязные» страницы (Dirty), а на диск уходит позже. Поэтому:
- после
cat bigfile > /dev/nullрастётbuff/cache, это хорошо; echo 3 > /proc/sys/vm/drop_cachesочищает кеш, но на проде это почти всегда вредно: следующие чтения пойдут на диск;- базы данных (PostgreSQL) полагаются на page cache, поэтому им нужен запас памяти сверх собственных буферов.
Виртуальная и резидентная память
- VSZ/VIRT: всё адресное пространство процесса: зарезервированное, отображённые файлы, библиотеки. Может быть гигантским и ничего не значить.
- RSS/RES: страницы, реально лежащие в физической памяти. Включает разделяемые библиотеки, поэтому сумма RSS всех процессов больше реального потребления.
- PSS: RSS, где общие страницы поделены между процессами. Честнее для подсчёта (
smem,/proc/<pid>/smaps_rollup).
Linux выделяет память лениво: malloc резервирует адреса, а физическая страница появляется при первой записи.
Overcommit
По умолчанию (vm.overcommit_memory = 0) ядро разрешает выделить больше, чем есть, с эвристической проверкой. Программы часто просят много, а используют мало. Обратная сторона: когда все одновременно начинают реально писать в память, её не хватает, и включается OOM killer.
Swap
Своп выгружает редко используемые анонимные страницы на диск. vm.swappiness (по умолчанию 60) задаёт, насколько охотно ядро свопит анонимную память по сравнению с выбросом page cache. Немного занятого свопа не проблема. Проблема, когда своп активен: ненулевые si/so в vmstat на каждом замере. Тогда всё тормозит, ведь доступ к диску на порядки медленнее RAM.
Для баз и сервисов с жёсткими задержками своп часто уменьшают или отключают. В Kubernetes узлы исторически работают без свопа.
OOM killer
Когда память кончилась и освободить нечего, ядро выбирает процесс и убивает его SIGKILL. Выбор по oom_score (видно в /proc/<pid>/oom_score): в основном по размеру потребления, с поправкой oom_score_adj от -1000 (никогда не убивать) до 1000.
Следы в журнале ядра:
dmesg -T | grep -i -E 'killed process|out of memory'
journalctl -k | grep -i oom
Out of memory: Killed process 1310 (java) total-vm:4800000kB, anon-rss:3900000kB, ...
Процесс, убитый так, завершается с кодом 137 (128 + 9).
cgroups: лимит на группу
Контейнеры и сервисы systemd живут в cgroup с лимитом памяти (memory.max в cgroup v2, MemoryMax= в юните, --memory в Docker, limits.memory в Kubernetes). При превышении лимита OOM срабатывает внутри группы, даже если на машине память есть. В Kubernetes это статус OOMKilled.
Учти: в лимит cgroup входит и page cache группы. Ядро сначала пытается освободить кеш, и только если не выходит, убивает процесс.
Утечка или нормальный рост
- Утечка: RSS процесса растёт без конца и не возвращается после снижения нагрузки.
- Нормальный рост: прогрев кешей, JIT, аллокатор не отдаёт память ОС сразу (glibc malloc, сборщики мусора).
- Для JVM и Node.js важно, что лимит кучи (
-Xmx,--max-old-space-size) должен быть меньше лимита контейнера: есть ещё стек, метапространство, буферы. Современные JVM сами читают лимит cgroup.
Частые ошибки
- Паниковать из-за маленького
freeпри большомavailable. - Складывать RSS всех процессов и получать больше, чем есть RAM.
- Чистить
drop_cachesпо крону. - Ставить
-Xmxравным лимиту контейнера. - Искать причину OOM в логах приложения: его убили
SIGKILL, он ничего не успел написать. Смотреть надоdmesg.
Что спросят на собесе
- Почему
freeмаленький, а это не проблема. Что такое available. - Чем VSZ отличается от RSS.
- Как работает OOM killer и как понять, что он сработал.
- Что такое swappiness и когда своп вреден.
- Почему контейнер убит по OOM, хотя на узле свободно 10 ГБ.