# mmap - файлы и shared memory _Процессы и ресурсы · LinuxLab Knowledge Base_ **TL;DR:** `mmap()` маппит файл (или анонимный регион) в virtual address space процесса. Любые read/write через указатель = операции с файлом. Основа shared memory. ## Идея Обычно работа с файлом: `open` → `read(fd, buf, n)` в свой буфер → работа с буфером. Это копирование: page cache → user buffer. С mmap: `open` → `mmap(fd)` → получаешь указатель → читаешь/пишешь как обычный массив. Никакого `read()`, ядро лениво подгружает страницы при page-fault'е. ```c int fd = open("data.bin", O_RDONLY); void *p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); // теперь p[42] = первый прочитанный байт; страница загрузится при первом обращении ``` ## Виды mappings **File-backed:** - `MAP_PRIVATE` - приватная копия. Запись не уходит в файл. Используется для загрузки бинарей/библиотек. - `MAP_SHARED` - изменения видны всем кто маппил тот же файл, в т.ч. сохраняются на диск. Это и есть shared memory через файл. **Anonymous** (`MAP_ANONYMOUS`, без fd): - `MAP_PRIVATE | MAP_ANONYMOUS` - обычный heap; так работает `malloc()` для больших аллокаций - `MAP_SHARED | MAP_ANONYMOUS` - shared между fork-чайлдами ## Зачем использовать - **БД и search engines** - постгрес, лусен, sqlite используют mmap для своих data-файлов. Page cache работает за них. - **Загрузка бинарей** - все ELF-файлы и `.so` маппятся (`/proc//maps`) - **Большие файлы random access** - mmap'ить, прыгать по offset'ам. Ядро прогружает только нужные страницы. - **IPC между процессами** - `MAP_SHARED` на одном файле = быстрый shared region между независимыми процессами. Без копирований. - **Memory-mapped I/O** для устройств (`/dev/mem`) ## /dev/shm - POSIX shared memory Это **tmpfs**, специально для shared mappings: ```c int fd = shm_open("/myseg", O_CREAT | O_RDWR, 0600); ftruncate(fd, 1024 * 1024); void *p = mmap(NULL, 1024*1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); // → p - указатель на 1 MB; другой процесс делает shm_open("/myseg") и видит то же самое ``` Файл по факту в `/dev/shm/myseg` - можно увидеть через `ls /dev/shm`. Размер `/dev/shm` обычно 50% RAM (tmpfs). Менять через mount: ```bash sudo mount -o remount,size=8G /dev/shm ``` Postgres использует `/dev/shm` для shared_buffers? **Нет** - обычно System-V shared memory или mmap файла напрямую. `/dev/shm` чаще используют redis, scientific computing, video processing. ## Когда mmap ВРЕДЕН - **Сетевые ФС** - NFS/CIFS могут давать стрёмные результаты (consistency через сеть) - **Огромные файлы > VAS на 32-bit** - на 32-bit системах VAS = 3-4 GB - **Append-heavy workload** - постоянно расширять mmap'нутый файл дорого; обычный `write()` лучше - **fault-storm** - random access к холодному файлу = тысячи major faults, может задохнуться ## madvise - подсказки ядру ```c madvise(addr, len, MADV_SEQUENTIAL); // буду читать последовательно - большой readahead madvise(addr, len, MADV_RANDOM); // случайно - отключить readahead madvise(addr, len, MADV_DONTNEED); // эти страницы больше не нужны - можно выкинуть madvise(addr, len, MADV_HUGEPAGE); // склеить в huge pages если возможно madvise(addr, len, MADV_DONTFORK); // не дублировать в child при fork ``` ## Дебаг и наблюдение ```bash cat /proc//maps # все mappings процесса pmap -x # с размерами/RSS cat /proc//smaps | head -30 # на каждый regional блок: # Size: 4 kB ← VSZ # Rss: 4 kB ← реально в RAM # Pss: 2 kB ← proportional (делится на shared) # Shared_Clean: 4 kB ← shared, чистая # Private_Dirty: 0 kB # Swap: 0 kB ``` PSS (Proportional Set Size) - лучшая метрика «реально использует»: shared библиотека на 100MB между 10 процессами даст каждому PSS = 10MB, RSS у каждого = 100MB. ## Связь с другими частями - **mmap файла + shared = page cache** ([page-cache](/kb/page-cache.md)). Та же страница видна и в обычном `read()`, и через `mmap`. - **Anonymous mmap** = heap = swap'ится при нехватке RAM ([swap](/kb/swap.md)) - **Все [process-and-pid](/kb/process-and-pid.md) процессы** разделяют `libc.so.6` через `MAP_PRIVATE`-mappings (read-only код shared) ## Команды ```bash cat /proc/$$/maps | head ``` Все mappings шелла - бинарь, либы, heap, stack ```bash pmap -x | tail -1 ``` Сводка: total VSZ + RSS процесса ```bash ls -l /dev/shm ``` POSIX shared memory сегменты - кто из приложений их использует ```bash cat /proc//smaps | grep -A1 heap ``` RSS/PSS heap-сегмента конкретного процесса ```bash ipcs -m ``` Старая System-V shared memory (отдельная подсистема от mmap) ## См. также - [Virtual memory - виртуальные адреса, page tables](/kb/virtual-memory.md) - [Page cache - диск в памяти](/kb/page-cache.md) - [File descriptors (stdin, stdout, stderr)](/kb/file-descriptors.md) - [io_uring - third-rank async I/O syscall](/kb/io-uring.md)