Своп (swap)
Своп (swap)
Своп — это место на диске, которое операционная система использует как «продолжение» оперативной памяти: туда вытесняются страницы памяти, которые сейчас не нужны, чтобы освободить место активным.
История
Идея простая, но появилась она не сразу. До конца 1950-х в компьютерах
программа целиком помещалась в основную память — и если не помещалась,
программисту приходилось вручную делить её на «оверлеи» и подгружать куски
с барабана. Это было больно, и каждый делал это по-своему.
Перелом — Atlas Computer (Манчестерский университет, 1962 год). Это был
один из первых компьютеров с виртуальной памятью и пейджингом.
Главный инженер — Том Килбёрн (Tom Kilburn), тот же человек, который раньше
построил Manchester Baby (первый в мире компьютер с хранимой программой,
1948 год). Идея Atlas была революционной: программа видит «непрерывное
адресное пространство», а ОС сама перебрасывает блоки между быстрой
магнитной сердечной памятью (16 тысяч слов) и медленным барабаном
(96 тысяч слов). Программист о существовании барабана даже не подозревает.
С тех пор все универсальные ОС эту идею переняли. Несколько вех:
- Multics (1965, MIT) — довёл виртуальную память до уровня «продакшен-системы».
- Unix v6 (1976) — там ещё был swapping в старом смысле: вытеснялся
целый процесс, а не отдельные страницы. На PDP-11 памяти было мало, ядро
гоняло процессы туда-сюда блоками. - 4.2BSD (1983) — переход на полноценный paging (постраничный обмен,
как в Atlas). С этого момента «свопом» стали называть и саму область
на диске, и сам процесс перемещения страниц. - Linux 0.95 (1992) — добавлен swap.
- Windows NT (1993) — там это называется page file (
pagefile.sys). - macOS — dynamic_pager: ОС сама создаёт и расширяет swap-файлы в
/private/var/vm/swapfile*, размер не ограничен заранее.
В 2010-х появился zram/zswap в Linux: сжатый своп прямо в RAM. Идея
красивая: лучше пожать страницу в 3 раза, чем гнать её на медленный диск.
Сегодня zram включён по умолчанию во всех Android-устройствах — у
телефонов мало RAM, и сжатие выигрывает у физического свопа.
Что это такое
Когда говорят «своп», обычно подразумевают одно из трёх:
- Swap space — место на диске (отдельный раздел или файл), куда ОС
вытесняет страницы памяти. На Linux это обычно/swapfileили раздел
с типомlinux-swap. На macOS — файлы в/private/var/vm/. На Windows
—pagefile.sysв корне системного диска. - Swapping (в широком смысле) — сам процесс вытеснения и подгрузки
страниц. Технически правильнее называть это paging, но в обиходе
«своп» прижилось. - Swapping (в узком, историческом смысле) — вытеснение целиком
процесса, как в Unix v6. Сейчас почти не встречается.
Что важно понять: своп — это не дополнительная память. Своп — это
иллюзия дополнительной памяти. Программам показывают, что памяти
хватает, но как только ОС начнёт реально читать и писать страницы с диска,
скорость работы упадёт в 1000–10000 раз. RAM отвечает за наносекунды,
NVMe SSD — за десятки микросекунд, обычный SATA SSD — за сотню микросекунд,
HDD — за миллисекунды. Между «всё помещается в RAM» и «активная работа
ушла в своп» — пропасть, которая мгновенно ощущается пользователем как
«система зависла».
Своп vs виртуальная память. Виртуальная память — более широкое понятие:
это сам механизм, при котором у каждого процесса своё виртуальное адресное
пространство, а ядро через таблицу страниц проецирует его на физическую
память. Своп — это расширение виртуальной памяти на диск. Виртуальная
память работает и без свопа (на встроенных системах часто так); своп без
виртуальной памяти невозможен.
Своп vs кэш. Иногда путают. Кэш файловой системы — это когда ОС держит
в RAM копии содержимого диска, чтобы повторное чтение было быстрым.
Своп — наоборот: ОС держит на диске копии содержимого RAM, чтобы
освободить место. Кэш — дополнительная скорость; своп — расплата за
нехватку памяти.
Аналогии из жизни
Стол и шкаф. Представь, что ты редактор: на столе лежат бумаги, с
которыми сейчас работаешь (RAM), а в шкафу — папки, которые могут
понадобиться (своп). Когда стол переполнен, ты убираешь самую старую папку
в шкаф, чтобы новая поместилась. Если кто-то спросит про эту старую — встал,
дошёл до шкафа, нашёл, принёс. Дольше, но влезло.
Где ломается: в реальности шкаф стоит рядом со столом, дорога занимает
секунды. Своп же медленнее RAM в тысячи раз — как если бы шкаф был
в соседнем здании на другом этаже, и за каждой папкой надо идти лично.
Холодильник и морозилка. Текущая еда лежит в холодильнике (RAM) — её
быстро достал и съел. Заготовки на потом — в морозилке (своп). Хранится
бесконечно, но прежде чем использовать, надо разморозить.
Где ломается: морозилка реально сохраняет еду и делает её более
компактной; своп ничего не «сжимает» в обычном смысле, он просто меняет
место (хотя есть исключение — zram/zswap, там как раз есть компрессия).
Парковка и гараж в спальном районе. Машины, которыми ты ездишь каждый
день, стоят на парковке у дома (RAM). Те, что для дачи или ралли, — в
гараже в Подмосковье (своп). Машин у тебя больше, чем мест на парковке,
но в любой момент времени активно используешь только несколько — и они
помещаются.
Где ломается: в реальной жизни поездка за машиной в гараж — это часы.
Своп всё-таки секунды, а не часы. Зато выбор «какую машину держать
ближе» делается тобой осознанно, а ОС решает это по алгоритму —
и иногда ошибается.
Как это работает
Чтобы понять своп, надо сначала понять три вещи: страницы, таблица страниц
и page fault.
Страница. Память делится на блоки фиксированного размера, обычно
4 КБ (на x86; на новых ARM — 16 КБ). Это атом памяти: всё, что ОС
вытесняет или возвращает в RAM, — это страницы целиком, никогда отдельные
байты.
Таблица страниц (page table). Для каждого процесса ядро ведёт таблицу:
«виртуальный адрес X → физический адрес Y». Таблица многоуровневая
(обычно 4 уровня на современных x86-64) — чтобы не хранить полную карту
для адресного пространства в десятки терабайт. У каждой записи есть флаги:
present (страница в RAM или нет?), dirty (была ли изменена?), accessed
(была ли прочитана недавно?), права доступа и т.д.
MMU и TLB. За проекцию виртуального адреса в физический отвечает
аппаратный блок процессора — MMU (Memory Management Unit). У MMU есть
встроенный кэш — TLB (Translation Lookaside Buffer), потому что
прохождение по 4-уровневой таблице страниц на каждый доступ к памяти
было бы слишком медленным.
Теперь — что происходит при свопе.
Шаг 1. Памяти стало мало. Допустим, у тебя 16 ГБ RAM, и активные
процессы хотят 17 ГБ. ОС запускает алгоритм выбора «жертвы» — какую
страницу выгнать. Самые известные алгоритмы:
- LRU (Least Recently Used) — выгнать ту, к которой дольше всего не
обращались. Идея простая, точная реализация дорогая (надо обновлять
список на каждый доступ), поэтому используются приближения. - Clock (Часы) — страницы выложены в кольцо, у каждой бит accessed.
Алгоритм идёт по кольцу: если бит=1, сбрасывает его и идёт дальше;
если бит=0 — выгоняет. Это дешёвое приближение к LRU. - WSClock — улучшение Clock, учитывающее «рабочий набор» (working set)
процесса. Используется в Linux в виде двусписочной LRU (active list
и inactive list).
Шаг 2. Запись на диск. Выбранную страницу ОС пишет в своп-область.
Если страница clean (содержимое совпадает с тем, что уже есть на диске,
например — код программы или mmap-нутый файл), записывать не надо — просто
пометить «отсутствует». Если dirty (была изменена) — записать.
Шаг 3. Освобождение. Запись в таблице страниц обновляется: флаг
present сбрасывается, в саму запись пишется номер блока в свопе.
Физическая страница в RAM теперь свободна.
Шаг 4. Page fault. Когда процесс обращается к этой странице, MMU видит
present=0 и вызывает прерывание — page fault. Управление переходит в
ядро. Ядро по записи в таблице понимает: страница в свопе. Находит
свободную страницу в RAM (возможно, выгоняя кого-то ещё), читает с диска,
обновляет таблицу, передаёт управление обратно процессу. Процесс об этом
не знал — он просто заметил, что одна инструкция выполнилась подозрительно
долго (миллисекунды вместо наносекунд).
Threshing (буксование). Самый неприятный режим. Если активный
working set всех процессов больше объёма RAM, ОС начинает выгонять
страницу, которая через секунду снова понадобится, потом возвращать её,
выгоняя соседнюю, и т.д. В итоге диск загружен на 100%, процессор простаивает,
полезной работы — ноль. Это и есть та самая «всё зависло, мышка дёргается
рывками». В Linux от threshing спасает OOM-killer: ядро решает, что лучше
прибить самый прожорливый процесс, чем продолжать буксовать.
Swappiness. В Linux есть параметр vm.swappiness (0–100, по умолчанию 60).
Это не процент памяти, который пойдёт в своп, как часто думают. Это
склонность ядра выгонять анонимные страницы (heap процессов) вместо
выкидывания страниц файлового кэша. 0 — «трогай своп в последнюю очередь»,
100 — «своп и file cache равнозначны». На серверах БД часто ставят 10
(потому что file cache важнее), на десктопах оставляют 60.
ASCII-схема цикла:
процесс ядро диск
| | |
| mov eax, [0x7f00] | |
| (виртуальный адрес) | |
|--> MMU ищет страницу | |
| в таблице страниц | |
| present=0! ---------------| |
| page fault -------------> | |
| | находит запись |
| | "в свопе, блок 1234" |
| | читает 4КБ ---------> |
| | <--- 4КБ через ~10мкс |
| | кладёт в физ. RAM |
| | обновляет MMU |
| <----------------------------| |
| продолжает с той инструкции | |
Где встречается в обычной жизни
- Телефон тормозит, когда переключаешься между чатами. Часть приложений
выгнана из RAM в zram (сжатый своп Android), и при возврате к ним нужно
расжать страницы и подгрузить. Если у тебя 4 ГБ RAM и 50 открытых вкладок
в Chrome — система буксует именно из-за свопа. - MacBook начинает гудеть вентилятором при множестве открытых вкладок.
Это macOS гоняет страницы в/private/var/vm/swapfile*. Проверить просто:
командаsysctl vm.swapusageпокажет, сколько использовано. - Windows «думает» при первом запуске тяжёлой программы после простоя.
Часть памяти за ночь ушла вpagefile.sys, теперь её надо вернуть. - Игра подтормаживает в начале уровня, потом идёт плавно. Текстуры
локации подгружаются из свопа в RAM (или из файла игры через mmap, что
технически другое, но ощущения те же). - Браузер с 100 вкладок просыпается из «зависа» после паузы. Tab
discarding отправил вкладки в своп, теперь их надо вернуть.
Где встречается в IT и бизнесе
- Серверы баз данных. Большая боль: если PostgreSQL или MySQL выйдут
в своп, latency запросов взлетит в сотни раз. На прод-серверах СУБД
часто отключают своп полностью (swapoff -a), полагаясь на OOM-killer. - VPS с 1–2 ГБ RAM. Дешёвые VPS выживают только за счёт свопа: иначе
Node.js или Python сразу падают. Но и работают они на грани — любая
всплеск нагрузки роняет latency в пол. - Локальный LLM-инференс. Это как раз вчерашний кейс: модель
gemma3:26b
занимает 18 ГБ, в 16 ГБ RAM не помещается, уходит в своп — и скорость
падает с 13 токенов/сек до ~1 ток/с. Запустить-то можно, пользоваться —
нет. - Контейнеры (Docker, Kubernetes). В cgroups v2 есть отдельный учёт
swap (memory.swap.max). По умолчанию Kubernetes своп отключает на
узлах — потому что метрики памяти становятся непредсказуемыми, и автоскейлер
не понимает, надо ли добавлять ноды. - Embedded и IoT. На устройствах с eMMC своп категорически выключают:
flash-память имеет конечное число циклов записи, своп её выжжет за месяцы.
Кто пользуется
- Все универсальные ОС: Linux, macOS, Windows, FreeBSD, OpenBSD,
Solaris. Без свопа из коробки работают только специализированные системы
(RTOS, embedded, гипервизоры в режиме «full memory pinning»). - Android — zram включён по умолчанию у всех вендоров с 2015 года
(Lollipop). На большинстве телефонов от 30 до 50% RAM может быть «сжатой». - ChromeOS — тоже zram плюс быстрая выгрузка вкладок.
- Apple Silicon Mac — благодаря unified memory architecture своп
работает заметно агрессивнее: macOS быстро отдаёт страницы графике,
CoreML, разным акселераторам, и активно использует swapfile при их
возврате. На MacBook с 8 ГБ это можно увидеть глазами — свопфайл легко
растёт до 10+ ГБ при обычной работе. - Дата-центры. На серверах своп — это страховка, а не основной механизм.
Хороший прод-сервер должен жить в RAM; своп нужен, чтобы при сбое
или аномальной нагрузке система не падала, а лишь замедлилась.
Цифры (примерные, по разным источникам):
- На типичном Android-телефоне (Pixel 8, 8 ГБ RAM) zram даёт эквивалент
ещё ~4 ГБ «памяти».
- На MacBook Air M2 с 8 ГБ свопфайл обычно держится 5–15 ГБ при средней
нагрузке.
- На прод-сервере PostgreSQL с 128 ГБ RAM swap часто 4 ГБ — символический,
«на всякий случай», и здоровая система к нему не прикасается.
Альтернативы и конкуренты
- Просто больше RAM. Самая честная альтернатива. Дорого один раз —
быстро всегда. - Плюс: предсказуемая latency.
- Минус: дорого, ограничено железом (для DDR5 на десктопе обычно 128 ГБ
потолок; для сервера дороже сильно). - zram (Linux/Android). Сжатый «своп» прямо в RAM, без диска.
- Плюс: в ~1000 раз быстрее свопа на SSD, потому что нет I/O.
- Минус: за сжатие/расжатие платит CPU; экономия памяти зависит от
содержимого (тексты сжимаются в 3 раза, бинарные данные — почти не
сжимаются). - zswap (Linux). Гибрид: zram как кэш перед обычным свопом на диске.
- Плюс: сочетает скорость и неограниченный размер.
- Минус: сложнее в настройке, больше движущихся частей.
- mmap + явное управление. Open-source подход: вместо системного свопа
программа сама проецирует большой файл в виртуальную память и при работе
с ним только нужные страницы подкачиваются с диска. Так делают многие
БД (LMDB, MongoDB до 3.2) и поисковики (Lucene). - Плюс: контроль на стороне приложения, никаких сюрпризов.
- Минус: программисту надо думать о паттернах доступа.
- Out-of-core / disk-based algorithms. Алгоритмы, которые изначально
спроектированы работать с данными больше RAM. Базы данных, файловые
системы, поисковые индексы. Это другой инженерный подход, чем «сделаем
вид, что RAM бесконечна». - Плюс: никаких сюрпризов на больших данных.
- Минус: сложнее в разработке.
Когда НЕ стоит использовать
- На СУБД-серверах (PostgreSQL, MySQL, Redis). Менеджер памяти СУБД
гораздо лучше ОС знает, какие страницы держать в RAM, а какие можно
отдать. Если СУБД сама уйдёт в swap — это всегда хуже, чем если бы она
получила «памяти больше нет, забери у меня». Поэтому: либо отключить
swap, либо поставитьvm.swappiness=1. - На latency-критичных приложениях: трейдинг, real-time, телефония,
игры с быстрым реагированием. Один page fault — это пропущенный кадр
или потерянная сделка. - На LLM-инференсе. Если модель плюс контекст не помещаются в RAM/VRAM
целиком, своп превратит «10 ток/с» в «0.5 ток/с». Тут стратегия одна:
взять модель поменьше или квантизацию поагрессивнее.
Самая частая ошибка
«Накину swap побольше — пусть памяти будет много». Своп не делает память больше, он позволяет не упасть при её нехватке. Программа, которая активно работает с 32 ГБ на 16-гиговой машине, будет работать в 1000 раз медленнее, а не «как бы с 32 ГБ».
Связанные понятия
- Page fault — прерывание процессора, когда программа обратилась к
виртуальному адресу, которого нет в RAM. Бывает minor (страница есть,
но не отображена) и major (нужно читать с диска). - Working set — набор страниц, активно используемых процессом в
данный момент. Если working set всех процессов > RAM — начинается
threshing. - Threshing (буксование) — патологический режим, когда система
тратит больше времени на свопинг, чем на полезную работу. - OOM killer — Out-Of-Memory killer в Linux. Когда даже своп не
спасает, ядро убивает самый прожорливый процесс по эвристике (можно
настроить черезoom_score_adj). - mmap — системный вызов, проецирующий файл в адресное пространство.
Похоже на своп наоборот: программа явно «свопит» с конкретным файлом. - TLB (Translation Lookaside Buffer) — кэш MMU. При переключении
процессов TLB сбрасывается, что замедляет первые несколько обращений. - Huge pages — большие страницы (2 МБ или 1 ГБ вместо 4 КБ). Меньше
записей в TLB, быстрее доступ, но плохо взаимодействуют со свопом. - NUMA — Non-Uniform Memory Access. На многосокетных серверах своп
одного сокета может уходить через шину к памяти другого сокета — это
отдельная категория тормозов.
Литература и источники
- Andrew Tanenbaum, «Modern Operating Systems» (Pearson, 2014, en, 4-е
издание). Глава 3 «Memory Management» — каноническое объяснение
пейджинга, алгоритмов LRU/Clock/WSClock, threshing. - Silberschatz, Galvin, Gagne, «Operating System Concepts» (Wiley,
10-е издание 2018, en и ru). Глава 9 «Virtual Memory». Учебник, по
которому учат в большинстве IT-вузов. - Brendan Gregg, «Systems Performance» (Addison-Wesley, 2-е издание
2020, en). Глава 7 «Memory» — практика наблюдения свопа в Linux:
vmstat,swapon -s,cat /proc/meminfo. - Wikipedia: «Paging»
(en.wikipedia.org/wiki/Paging),
«Virtual memory», «Atlas (computer)». Хорошие обзорные статьи, особенно
про Atlas — историческая часть с фото и схемами. - Документация Linux:
man swapon,man 5 proc(раздел про
/proc/swaps,/proc/meminfo),man sysctl(проvm.swappiness,
vm.overcommit_memory). - Apple Developer Documentation — поиск по «dynamic_pager» и
«compressed memory». macOS использует ещё и компрессию в RAM (как
zram), это документировано.
Где встретилось у меня
Вчера на Mac mini (16 ГБ) поднял Ollama с моделью Gemma 12B — пошло
хорошо. Когда попробовал прикинуть Gemma 26B, выяснилось, что она не
помещается в видеопамять (11.8 ГБ) и даже в общую (16 ГБ): либо не
загрузится, либо уйдёт в своп — и инференс упадёт с 13 токенов/сек
до примерно одного. Параллельно на VPS обнаружил, что справочник ЖК
ест 1.7 ГБ RSS, и хост сидит на 1.7 ГБ свопа — тонкий запас, любая
ещё одна утечка начнёт замедлять соседние сервисы.
Главный вывод дня
Своп — это не «дополнительная память», а способ не упасть, замедлившись в тысячу раз. Если приложение должно держать N гигабайт active set, у него должно быть N гигабайт RAM. Точка. Своп — страховка, не план.
Краткое резюме
- Своп — это место на диске, куда ОС вытесняет неактивные страницы памяти,
чтобы освободить RAM для активных. Иллюзия дополнительной памяти, не
расширение. - Изобретён в 1962 году на компьютере Atlas (Манчестер, Том Килбёрн);
с тех пор есть во всех универсальных ОС. - Доступ к свопу медленнее RAM в 1000–10000 раз. Активное использование
свопа = всё «тормозит». - Threshing — самый болезненный режим: ОС больше времени тратит на
свопинг, чем на работу. Спасает либо OOM-killer, либо ручное вмешательство. - Хорошая стратегия для прода: своп должен быть как страховка (на случай
всплеска), но здоровая система к нему не прикасается. На СУБД-серверах
и при LLM-инференсе своп — это всегда боль.