Зачем вообще нужен swap и почему «свободная RAM» — не аргумент
Swap в Linux — это не «память на случай, когда всё плохо», а часть общей политики управления памятью. Ядро постоянно балансирует между анонимной памятью (heap/stack процессов), файловым кэшем (page cache), slab-объектами, буферами и другими потребителями. Поэтому ситуация free ram but swapping часто нормальна: «свободно» в выводе утилит означает «не занято прямо сейчас», но не гарантирует, что память доступна без потерь производительности.
Ключевая мысль: Linux старается держать RAM полезно занятой (например, кэшем файлов). При этом он может заранее вытеснять часть «холодной» анонимной памяти в swap, чтобы сохранить page cache, подготовиться к будущим аллокациям, снизить фрагментацию или уложиться в лимиты cgroup.
Swap-активность сама по себе не является проблемой. Проблема — это задержки из‑за постоянного reclaim/IO или внезапные убийства процессов OOM, когда память заканчивается «по факту», а не «по цифрам».
Быстрый чек-лист: что посмотреть в первую минуту
Когда вы видите рост swap usage или жалобы на «тормоза», начните с проверки: есть ли реальная активность свопинга прямо сейчас (а не просто занятый swap), есть ли давление по памяти (PSI), не ограничивает ли вас cgroup, и не упирается ли swap в медленный диск/хранилище.
- Swap занят или именно «шевелится»?
- Есть ли stalls по PSI для memory?
- Есть ли контейнеры/systemd-слайсы с жёсткими лимитами?
- Какой носитель у swap (и что с IO)?
- Используется ли zram и не стало ли CPU узким местом?
Если вы администрируете проекты на VDS, полезно заранее заложить мониторинг PSI и swap-in: при дефиците RAM это быстрее всего выдаёт реальную деградацию, а не «красивые» проценты занятости.

Как читать swap usage правильно: занято — не значит «свопим»
Важно различать две ситуации:
- Swap занят — в нём лежат страницы, выгруженные раньше. Это может быть «исторический след» пиков нагрузки и вообще не мешать.
- Идёт свопинг сейчас — страницы активно пишутся/читаются. Это уже нагрузка на диск и потенциальные задержки, особенно при swap-in.
Типичная ловушка: вы видите, что swap занят, но система работает быстро. Это нормально, если swap-in почти не происходит, а swap-out редок и не постоянный.
vmstat: ключевые поля si/so и как не ошибиться
Для диагностики в реальном времени удобно начать с vmstat (часто ищут именно «vmstat si so»):
vmstat 1
Смотрите на:
si— swap in: страницы читаются из swap в RAM. Обычно это самое болезненное (даёт latency).so— swap out: страницы пишутся в swap. Само по себе может быть терпимо, если это не фон и диск быстрый.r,b— очереди на выполнение и блокировки (косвенно указывают на «залипание»).wa— ожидание IO (полезно в связке сsi/so).
Практическая интерпретация:
- Высокий
soпри низкомsi: ядро «разгружает» анонимную память (часто после всплеска). Может быть нормальным. - Регулярный высокий
si: процессы постоянно «достают» страницы из swap. Почти всегда даёт лаги. siиsoрастут вместе и постоянно: типичный thrashing — памяти объективно не хватает или лимиты cgroup слишком жёсткие.
swappiness: что делает параметр и почему «поставить 1» — не универсальный совет
swappiness — это не «включатель swap», а коэффициент, влияющий на то, насколько охотно ядро будет вытеснять анонимную память по сравнению с освобождением page cache. Диапазон обычно 0–100; в современных ядрах 0 не означает «swap выключен навсегда».
Посмотреть текущее значение:
sysctl vm.swappiness
Временно изменить (до перезагрузки):
sysctl -w vm.swappiness=10
Ориентиры по практике:
- 1–10 — чаще для latency-чувствительных сервисов (веб/API), где swap нужен как «подушка», но не как рабочая область.
- 20–40 — умеренный вариант для смешанных нагрузок.
- 60+ — иногда уместно, если важнее удержать файловый кэш и есть «холодные» страницы, к которым редко возвращаются.
Почему опасно бездумно занижать swappiness: если вы фактически запрещаете ядру выгружать «холодную» анонимку, оно может агрессивнее чистить page cache. Итог — чтение файлов становится дороже, аллокации нестабильнее, а в контейнерах при жёстких лимитах вы быстрее увидите OOM.
/proc/meminfo: какие строки помогают понять «почему свопит»
/proc/meminfo — базовый источник правды. Снимите состояние одной командой:
grep -E 'MemTotal|MemFree|MemAvailable|Buffers|Cached|SwapTotal|SwapFree|AnonPages|Active\(|Inactive\(|SReclaimable|Shmem|Dirty|Writeback' /proc/meminfo
На что смотреть в первую очередь:
MemAvailable— лучшая оценка «сколько можно выделить без боли». Обычно важнееMemFree.CachedиBuffers— файловый кэш (это не «потерянная» память).AnonPages— объём анонимной памяти (то, что потенциально уходит в swap).Shmem— shared memory (tmpfs, /dev/shm); бывает «тихим пожирателем» памяти.SReclaimable— часть slab, которую можно reclaim (полезно при подозрении, что «ядро съедает память»).
Сценарий «free RAM but swapping» часто выглядит так: MemFree вроде неплохой, Cached большой, MemAvailable уже не так велик, а часть анонимной памяти лежит в swap — потому что ядро решило удерживать page cache.
/proc/vmstat: счётчики свопинга и reclaim, которые не видно в top
/proc/vmstat содержит накопительные счётчики с момента загрузки. Полезно смотреть динамику — прирост за 30–60 секунд, а не абсолютные значения.
egrep 'pswpin|pswpout|pgscan|pgsteal|pgfault|pgmajfault|oom_kill|compact' /proc/vmstat
Если растут:
pswpinиpswpout— идёт активный свопинг (особенно важен ростpswpin).pgmajfault— много major page faults (часто означает чтение с диска; не только swap, но симптом неприятный).pgscan*при слабомpgsteal*— reclaim «крутится», но мало что может отнять: признак давления памяти или плохого профиля нагрузки.
Memory Pressure PSI: как понять, что система реально страдает
PSI (Pressure Stall Information) отвечает на главный вопрос: простаивают ли процессы из‑за нехватки ресурса. Для памяти PSI показывает долю времени, когда задачи были вынуждены ждать из‑за reclaim/swap-in и других механизмов освобождения памяти.
Смотреть PSI по памяти:
cat /proc/pressure/memory
Обычно вывод содержит строки some и full с метриками avg10, avg60, avg300:
some: часть задач периодически простаивает из‑за давления памяти.full: все задачи одновременно испытывают stall — это уже серьёзная деградация.
Важно: PSI может быть высоким даже при умеренном swap usage, если reclaim тяжёлый (медленный диск, много конкурирующего IO, грязные страницы, compaction). И наоборот: swap может быть занят, но PSI низкий — значит, страданий «здесь и сейчас» нет.

Контейнеры и systemd: cgroup swap и «OOM при свободной памяти»
В современных дистрибутивах часто используется cgroup v2: память и swap лимитируются на уровне групп. Отсюда неожиданные ситуации, когда «на хосте ещё есть RAM», но конкретный контейнер/сервис начинает свопить или падает по OOM.
Базовые файлы в cgroup v2, которые стоит знать:
memory.current— текущее потребление памяти;memory.max— лимит памяти;memory.swap.current— текущее потребление swap;memory.swap.max— лимит swap;memory.events— события давления и OOM;memory.pressure— PSI на уровне cgroup.
Пример для systemd-сервиса: узнать cgroup и посмотреть лимиты/события.
systemctl status your-service-name
systemctl show -p ControlGroup your-service-name
Далее подставьте путь из ControlGroup:
cat /sys/fs/cgroup/<CGROUP_PATH>/memory.max
cat /sys/fs/cgroup/<CGROUP_PATH>/memory.swap.max
cat /sys/fs/cgroup/<CGROUP_PATH>/memory.events
cat /sys/fs/cgroup/<CGROUP_PATH>/memory.pressure
Типовые кейсы:
memory.maxмаленький, swap разрешён: группа начинает свопить даже при свободной RAM на хосте — потому что «RAM кончилась» внутри лимита.- swap запрещён (
memory.swap.max=0): при всплеске анонимной памяти получите OOM внутри cgroup, даже если на хосте swap есть.
Если вы часто упираетесь в лимиты systemd/cgroup в веб-стеке, пригодится разбор практики: как выставлять лимиты MemoryMax/CPUQuota в systemd без сюрпризов и статья про кейсы с PHP-FPM: systemd-слайсы и память для PHP-FPM.
OOM killer: почему он срабатывает и как понять, кого и за что убили
Когда ядро не может удовлетворить запросы памяти и не может эффективно reclaim или свопить, запускается механизм OOM. В контейнерах он часто срабатывает «локально» (cgroup OOM), поэтому выглядит как загадка: «на сервере же ещё есть память».
Минимальная практика расследования:
journalctl -k -b | egrep -i 'oom|out of memory|killed process'
И проверьте memory.events нужной cgroup: там обычно видно рост счётчиков oom или oom_kill.
zram: быстрый «компрессированный swap» и когда он помогает
zram создаёт блочное устройство в RAM и хранит в нём данные в сжатом виде. Это «swap в памяти», который часто выигрывает за счёт компрессии: вместо 1 ГБ несжатых страниц иногда удаётся удержать 1.5–2 ГБ логического объёма (зависит от данных и алгоритма). Но zram не бесплатен: он тратит CPU на сжатие и распаковку.
Когда zram полезен:
- на небольших серверах, где дисковый swap медленный или IO постоянно занят;
- для кратковременных всплесков памяти, когда лучше потратить CPU, чем уйти в дисковый swap и получить большие задержки;
- чтобы снизить риск OOM и «смягчить» пики.
Когда zram может навредить:
- CPU уже на пределе и компрессия ухудшает latency;
- нагрузка по памяти постоянная и высокая — zram будет всё время «молотить», но дефицит RAM это не исправит.
Проверить, есть ли активный zram:
lsblk | grep -i zram
swapon --show
Если хотите отдельный чек-лист именно для небольших серверов (swap, zram, пороги PSI, типовые настройки), посмотрите: память на VDS: swap и zram без мифов.
Практические сценарии и действия
1) Swap занят, но vmstat si почти 0: ничего не трогаем
Если si нулевой или почти нулевой, PSI по памяти низкий и сервисы не тормозят — не надо «срочно чистить swap». Чаще всего это след прошлого пика: страницы выгружены и лежат в swap, потому что к ним не обращаются.
2) Постоянный swap-in: ищем источник давления
Если растёт si и одновременно растут задержки, действуйте по шагам:
- Проверьте PSI:
cat /proc/pressure/memoryи подтвердите stalls. - Проверьте cgroup-лимиты (в контейнерах и systemd): возможно, проблема локальная, а не системная.
- Сверьте
/proc/meminfo:MemAvailable,AnonPages, не раздувается лиShmem. - Посмотрите
/proc/vmstat: растут лиpswpin,pgmajfault,pgscan*. - Дальше выбирайте действия: оптимизация приложения (утечки/кэши), увеличение RAM, пересмотр лимитов, zram, настройка swap.
3) «Свопит при свободной памяти»: норма или конфигурационная проблема
Обычно причина одна из трёх:
- нормальная политика: большой page cache, а «холодная» анонимка выталкивается (особенно при умеренном
swappiness); - cgroup-эффект: группа упёрлась в
memory.maxи начала свопить, хотя хост свободен; - реальный дефицит доступной памяти:
MemFreeесть, ноMemAvailableмал, и давление уже началось.
Нужно ли отключать swap?
Полное отключение swap редко лучший выход. Без swap любой пик анонимной памяти быстрее приводит к OOM, ядру сложнее переживать кратковременные всплески, а ошибки лимитов в контейнерах проявляются жёстче.
Чаще разумнее: держать небольшой swap как страховку, настроить адекватный swappiness, следить за PSI и не допускать постоянного swap-in.
Мини-набор команд для регулярной диагностики (копипаста)
Собрать картину «в моменте» одной пачкой:
date
uname -a
free -h
swapon --show
vmstat 1 10
cat /proc/pressure/memory
grep -E 'MemTotal|MemFree|MemAvailable|Buffers|Cached|SwapTotal|SwapFree|AnonPages|Shmem|SReclaimable' /proc/meminfo
egrep 'pswpin|pswpout|pgscan|pgsteal|pgmajfault|oom_kill' /proc/vmstat
Если под подозрением systemd-сервис:
systemctl show -p ControlGroup -p MemoryMax -p MemorySwapMax your-service-name
Итоги: как мыслить про swap, чтобы не лечить «симптомы»
Swap usage — это след решений ядра о том, какие страницы и когда выгрузить. Сам по себе процент занятости swap не отвечает на вопрос «плохо или нет». Для админа важнее:
- есть ли активный swap-in (смотрим
vmstatи/proc/vmstat); - есть ли stalls по PSI (смотрим
/proc/pressure/memory); - не ограничивает ли вас cgroup (смотрим
memory.max,memory.swap.maxиmemory.events); - какой профиль нагрузки (анонимка vs файловый кэш) по
/proc/meminfo; - что выгоднее: добавить RAM, поправить лимиты, включить/настроить zram или оптимизировать приложение.
Если нужно быстро «закрыть вопрос» на проекте, обычно проще всего начать с правильных лимитов и достаточного объёма памяти на сервере. В этом плане удобнее работать на предсказуемой конфигурации VDS, где вы контролируете swap, zram и политику systemd/cgroup под конкретную нагрузку.


