Процесс работает с виртуальными адресами; ядро отображает страницы на RAM или диск. RSS — то, что реально в памяти. Page cache ОС ускоряет чтение файлов и часто WAL, и это не Redis и не куча Go.
Операционные системы cs собеседование
Каждый процесс видит своё линейное адресное пространство: код, куча, стеки, mmap. Физические фреймы RAM общие, их распределяет ядро.
MMU и таблицы страниц переводят виртуальный адрес в физический. Пока страница не нужна, её может не быть в RAM. Будет page fault: ядро подложит фрейм или прочитает с диска (файл, swap, анонимная страница).
Пример. VSZ — сколько адресов процесс «забронировал». RSS — сколько страниц реально лежит в планках памяти. Забронировать стадион и занять три кресла — разные числа. Лимиты контейнера смотрят в первую очередь на занятые кресла (RSS), не на бронь (VSZ).
VSZ (виртуальный размер) часто огромный: зарезервировали диапазон, mmap'нули файл, Go выделил arena впрок. Это не значит, что столько же занято планками. RSS — резидентные страницы, те, что сейчас в RAM.
Page cache — кэш содержимого файлов в свободной RAM. Прочитали конфиг, бинарник, сегмент WAL — страницы остаются, пока нет давления памяти. Повторное чтение того же файла часто идёт из RAM. «Диск медленный» не всегда правда на прогретом сервере. Это кэш ядра. Не ключ-значение в Redis. Не объекты в куче Go.
RSS, VSZ и fault
Minor page fault — таблицы страниц, страница уже в памяти (например, shared). Major — нужно I/O. Рост RSS после старта процесса — нормальный прогрев: код, куча, кэш запросов. Скачок без отдачи — утечка в приложении или раздутый кэш внутри процесса (map, буферы).
// VA (процесс) --MMU--> PA (RAM) или диск / отсутствует
//
// VSZ = размер адресного пространства (резервы, mmap, стеки)
// RSS = страницы, которые сейчас в RAM
// file-backed page → можно вытеснить, перечитать с диска
// anonymous page → куча, стеки: swap или OOM, не «просто cache»
//
// cgroup memory.max ≈ давление на RSS.
// page cache ОС shrinking под давлением;
// Go heap так не отдаётся — нужен GC / меньше живых объектов.
Виртуальный адрес не равен байту RAM. Лимит контейнера режет RSS; page cache ядро может отдать, анонимную кучу Go — нет.
Page cache и база
Postgres читает страницы через ОС и через свой shared_buffers. Прогретый page cache делает Seq Scan дешевле, чем на холодном диске. После рестарта машины кэш пустой — те же запросы «внезапно медленные».
WAL тоже файлы: sequential write плюс cache. Это не отменяет fsync для durability. Кэш не замена записи на стабильное устройство.
Пример. Первый SELECT после ребута сервера читает страницы с диска — медленно. Второй такой же — часто уже из page cache ОС. Это не Redis и не «Postgres стал умнее». Это свободная RAM, в которой ядро держит недавно прочитанные файлы.
Контейнер и OOM
OOM killer и cgroup OOM смотрят на давление памяти. Огромный page cache ядро обычно отдаёт под анонимную память. Куча Go — анонимные страницы: GC должен освободить объекты, иначе RSS не падает.
Лимит памяти пода бьёт в RSS. VSZ «какой угодно» без резидентных страниц сам по себе лимит не превышает. Не путайте OS cache с Redis: вытеснение файла из page cache прозрачно. Ключ в Redis живёт по политике Redis.
Типичная ошибка
Смотреть на VSZ в top и кричать «утечка гигабайта». Или считать page cache «занятой бесполезной памятью» и выключать его. Ещё хуже — ждать, что лимит контейнера сначала съест только cache, а куча Go останется неприкосновенной: под давлением умрёт процесс с большим RSS heap.
На собеседовании
VSZ — бронь адресов, RSS — страницы в RAM. Анонимные страницы (куча Go) ядро не отдаёт как file-backed page cache. Лимит контейнера бьёт по RSS. OS page cache ≠ Redis ≠ L1 процессора.