# Page cache - диск в памяти _Процессы и ресурсы · LinuxLab Knowledge Base_ **TL;DR:** Page cache - кеш в RAM для содержимого файлов. Любое чтение/запись ФС идёт через него. «Used» в free выглядит большим, но page cache - это availabe. ## Зачем Disk slow, RAM fast. Page cache держит блоки файлов в памяти, чтобы: 1. Повторное чтение того же файла не лезло на диск 2. Запись возвращалась мгновенно (writeback позже) 3. mmap-файлы работали без явного `read()` Это **прозрачно**: программы пишут в обычные файлы, ядро само кеширует. Управление - большая часть `linux-vm` подсистемы. ## free -h: что значат колонки ``` total used free shared buff/cache available Mem: 16Gi 4.0Gi 500Mi 100Mi 12Gi 11Gi Swap: 4Gi 0 4Gi ``` - **used** - реально занято процессами + ядром - **free** - никем не используется (обычно мало!) - **buff/cache** - page cache; **доступно процессам по требованию** - **available** - оценка сколько новый процесс реально получит (примерно used + reclaimable cache) «Linux ate my RAM» - миф. Если `available` большой - всё ок, кеш отдадут под allocation мгновенно. Главное смотреть на **available**, не на free. ## Buffers vs Cache Исторически: - **Buffers** - кеш block-level (raw блоки устройства) - **Cache** - кеш ФС-уровня (файлы) На современных kernel'ах разница почти стёрлась, оба попадают в page cache. В `free` они сложены в `buff/cache`. ## Dirty pages и writeback Когда программа **пишет** в файл, страница помечается **dirty** (грязная). Ядро сбрасывает её на диск асинхронно - через **writeback**. ```bash cat /proc/meminfo | grep -E 'Dirty|Writeback' # Dirty: 12 MB ← модифицированы, ещё не на диске # Writeback: 0 MB ← в процессе записи прямо сейчас ``` Контролируется sysctl'ями: ```bash cat /proc/sys/vm/dirty_ratio # % RAM с которого ЗАСТАВЛЯЕТ записать (default 20) cat /proc/sys/vm/dirty_background_ratio # % с которого начинает в фоне (default 10) cat /proc/sys/vm/dirty_expire_centisecs # как долго dirty может ждать (default 30s) ``` Слишком большой dirty_ratio = долгие fsync-stall'ы при сбросе. Слишком маленький = больше I/O. На прод-БД часто тюнят. ## sync, fsync, sync() ```bash sync # сбросить ВСЕ dirty pages всех ФС (можно перед reboot) ``` В программах: - `fsync(fd)` - гарантирует что данные файла на диске - `fdatasync(fd)` - то же, но без метаданных (быстрее) - `O_SYNC` флаг при `open()` - каждая запись синхронная (медленно) БД и журнальные системы используют fsync на каждый commit - отсюда важность fast NVMe vs HDD для transaction throughput. ## drop_caches - освободить кеш руками ```bash sync # сначала сбросить dirty echo 3 | sudo tee /proc/sys/vm/drop_caches # 1=pagecache 2=dentries+inodes 3=всё ``` Зачем: бенчмаркить cold-cache производительность, провоцировать reload, debugging. На проде НЕ делать - потом первое чтение большого файла станет тормозным. ## Direct I/O - обход кеша Когда программа **сама** управляет кешированием (БД, видеоплееры): ```c open(path, O_DIRECT | O_RDWR, ...); ``` Чтение/запись летят прямо на диск, минуя page cache. Минус - все размеры и offset'ы должны быть выровнены по сектору. ## Readahead Ядро видит последовательное чтение файла и **превентивно** загружает следующие блоки - `readahead`: ```bash blockdev --getra /dev/sda # размер readahead в 512-байтных секторах blockdev --setra 16384 /dev/sda # увеличить (для streaming workload) ``` Большой readahead помогает sequential, мешает random (читает то что не пригодится). ## fadvise / madvise Программа может **подсказать** ядру: - `posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)` - «забудь этот файл из кеша» (после копирования больших файлов хорошо звать, чтобы не вытесняли горячие данные) - `POSIX_FADV_SEQUENTIAL` - увеличить readahead - `POSIX_FADV_RANDOM` - отключить readahead Утилита `vmtouch` - портит/прогревает кеш руками для бенчмарков. ## Page cache в [cgroups](/kb/cgroups.md) v2 В контейнере page cache считается per-cgroup. Лимит `memory.max` включает и кеш. Поэтому контейнер с маленьким лимитом памяти, читающий большой файл, может OOM'нуться даже без heap-allocations. ## Команды ```bash free -h ``` Память + page cache; смотрим на 'available', не на 'free' ```bash cat /proc/meminfo | grep -E 'Cached|Buffers|Dirty' ``` Подробный break down: сколько в кеше, сколько ждёт writeback ```bash sync && echo 3 | sudo tee /proc/sys/vm/drop_caches ``` Очистить кеш для бенчмарка cold-cache (НЕ на проде) ```bash sudo sysctl -w vm.dirty_background_ratio=5 ``` Снизить порог фонового writeback - для БД-тюнинга ```bash vmtouch /var/lib/postgres/base ``` Прогреть в кеш конкретный путь (если установлен vmtouch) ## См. также - [Virtual memory - виртуальные адреса, page tables](/kb/virtual-memory.md) - [mount и /etc/fstab - подключение ФС](/kb/mount-and-fstab.md) - [mmap - файлы и shared memory](/kb/mmap.md) - [io_uring - third-rank async I/O syscall](/kb/io-uring.md)