ZIM-НИЙ SAAALEЗимние скидки: до −50% на старт и −20% на продление
до 31.01.2026 Подробнее
Выберите продукт

memfd_create и «пропавшая» память: почему du не сходится с df и как найти deleted files через /proc, lsof и smaps

Если df показывает занятое место, а du «не видит» файлы, или RAM уходит без ясных причин, часто виноваты deleted files или shmem/memfd-маппинги. Пошагово разберём lsof +L1, /proc/pid/fd и smaps_rollup/smaps, чтобы быстро найти PID и реальный вклад в память, и понять, что делать дальше.
memfd_create и «пропавшая» память: почему du не сходится с df и как найти deleted files через /proc, lsof и smaps

Зачем вообще memfd_create и почему от него «пропадает» память

memfd_create — системный вызов Linux, который создаёт анонимный файловый объект и возвращает файловый дескриптор. Для приложения это «файл»: его можно читать/писать, делать mmap, передавать через Unix-сокеты другим процессам. Но хранится он в памяти (учёт обычно идёт через shmem/tmpfs и связанные маппинги), а не как обычный файл на диске.

Практически memfd встречается в браузерах, песочницах, JIT-компиляторах, контейнерных рантаймах, агентах обновления и сервисах, которые не хотят оставлять следы во временных каталогах. Для администратора это иногда выглядит как «пропала RAM»: на диске пусто, du ничего не показывает, а MemAvailable падает.

Параллельно есть классическая история с deleted files: файл удалён из дерева каталогов, но процесс держит открытый дескриптор. Тогда df видит занятое место (иноды/блоки всё ещё аллоцированы), а du — нет, потому что имени уже нет. По ощущениям это очень похоже на memfd: «объект есть, а пути нет», только в случае deleted files чаще страдает место на диске, а в случае memfd — RAM.

du vs df: почему цифры расходятся (и это нормально)

du суммирует размеры файлов, которые достижимы по путям в каталоге. df показывает занятое место на уровне файловой системы: всё, что реально заняло блоки/иноды, включая уже удалённые из каталога, но ещё открытые файлы.

Типовые причины расхождения:

  • deleted files: лог удалили/ротировали, но процесс продолжает писать в старый inode.
  • Права доступа: du не может зайти в каталог и пропускает часть дерева.
  • Снапшоты/CoW (btrfs/zfs/lvm): df учитывает физические блоки, du видимую версию.
  • Разные точки монтирования: du уходит в примонтированное, а df смотрит конкретную ФС.

Важно не смешивать плоскости: memfd почти всегда про память (shmem/tmpfs/анонимные маппинги), а расхождение du/df — чаще про дисковую ФС и удалённые, но открытые файлы.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Перед тем как углубляться в диагностику, зафиксируйте базовые метрики: свободное место по df, реальную видимую файловую «массу» по du и динамику памяти по free/vmstat. Это поможет отделить «утекло место на диске» от «давит память».

Вывод lsof +L1 с удалёнными, но открытыми файлами и сравнение du и df

deleted files: как быстро найти виновника через lsof +L1

Самый быстрый способ найти процессы, удерживающие удалённые файлы, — lsof +L1. Опция +L1 выводит файлы с количеством ссылок меньше 1: они удалены из каталога, но ещё открыты.

lsof +L1

Если вывод огромный, начните с среза:

lsof +L1 | head -n 50

Смотрите на SIZE/OFF и на путь с пометкой (deleted) — именно эти inode держат место, которое видит df, но не видит du.

Практический подход: если это логи, правильнее заставить процесс переоткрыть файлы (релоад/сигнал, если поддерживается) или сделать контролируемый перезапуск. «Удалить ещё раз» не поможет: имени уже нет, и inode освободится только при закрытии последнего дескриптора.

/proc/<pid>/fd: что на самом деле открыто у процесса

Когда нашли PID, идите в /proc: каталог /proc/<pid>/fd содержит симлинки на все открытые дескрипторы (файлы, сокеты, anon_inode и т.д.). Это полезно даже в минимальных окружениях, где нет lsof.

ls -l /proc/1234/fd

Признаки:

  • удалённый файл будет с (deleted) в конце;
  • memfd обычно выглядит как /memfd:NAME (имя задаёт приложение), то есть путь «псевдофайловый», а объект живёт в памяти.

Быстрые фильтры по одному процессу:

ls -l /proc/1234/fd | grep '(deleted)'
ls -l /proc/1234/fd | grep memfd

tmpfs/shmem и «память как файловая система»: где здесь место memfd_create

С точки зрения учёта Linux memfd тесно связан с shmem/tmpfs: объект существует как «файл», но его страницы — это память. Поэтому при расследовании «куда делась RAM» полезно посмотреть на tmpfs, но помнить, что цифры не всегда напрямую отвечают на вопрос «кто виноват»: страницы могут быть shared, могут переходить в private из-за COW, а часть может по-разному вести себя под давлением памяти.

Быстрые команды для контекста:

mount | grep tmpfs
df -hT | grep tmpfs

Если у вас наблюдается регулярное давление на память, имеет смысл параллельно привести в порядок лимиты/воркеры сервисов. Для веб-стека это часто начинается с тюнинга пулов и лимитов: пригодится разбор настройки PHP-FPM под нагрузку на VDS.

Почему RSS не отвечает на вопрос «кто съел RAM»

Частая ловушка — смотреть только RSS в ps/top. RSS показывает резидентный набор страниц процесса, но:

  • не объясняет, какие страницы shared (и кто «платит» за них);
  • не даёт детализации по типам маппингов (heap/stack/file-backed/shmem/anonymous);
  • может казаться «нормальным», пока значимая часть памяти распределена через shared mappings.

Для более честной оценки используйте PSS (proportional set size): shared-страницы делятся пропорционально числу процессов. Главный источник — /proc/<pid>/smaps и суммарный /proc/<pid>/smaps_rollup.

Схема memory mappings процесса с полями smaps: PSS, RSS и Private_Dirty

smaps и smaps_rollup: как увидеть anonymous mappings, shmem и вклад процесса

/proc/<pid>/smaps детализирует каждый memory mapping: диапазон адресов, права, backing (если есть) и метрики Rss, Pss, Private_Clean, Private_Dirty, Shared_Clean, Shared_Dirty и другие. Здесь обычно видно, где у процесса heap/stack/anon, где file-backed, где shmem/tmpfs/memfd.

Для быстрого итога по процессу используйте smaps_rollup:

cat /proc/1234/smaps_rollup

1) Снять PSS/RSS по группе процессов

Если сервис порождает воркеры, смотрите PSS суммарно (а не только RSS каждого):

for p in $(pgrep -f 'your-service-name'); do echo "== PID $p =="; grep -E '^(Rss|Pss):' /proc/$p/smaps_rollup; done

2) Найти маппинги memfd/shmem внутри smaps

В smaps заголовок каждого маппинга содержит «имя» (путь или метку). Часто достаточно точечного поиска:

grep -n 'memfd' /proc/1234/smaps | head -n 50
grep -nE 'shmem|/dev/shm|tmpfs' /proc/1234/smaps | head -n 50

Дальше оценивайте соседние строки с Pss и особенно Private_Dirty: это то, что сложнее «отжать» без влияния на процесс и что чаще всего становится причиной реального давления памяти.

Связка fd и smaps: как подтвердить, что «файл в памяти» реально съедает RAM

Сам факт наличия /memfd:... в /proc/<pid>/fd не доказывает, что именно он съедает память: дескриптор может быть открыт, но страницы не обязаны быть реально резидентными. Подтверждение делается через smaps: находите соответствующие маппинги и смотрите их Pss/Rss/Private_Dirty.

Рабочий порядок расследования:

  1. Фиксируете симптомы: падение MemAvailable, рост swap, OOM.
  2. Находите PID(ы), которые коррелируют по памяти (любым привычным способом).
  3. Проверяете ls -l /proc/<pid>/fd на memfd и (deleted).
  4. Смотрите /proc/<pid>/smaps_rollup, затем точечно /proc/<pid>/smaps по найденным меткам.

Идея простая: виноват не «memfd вообще», а конкретные страницы. Поэтому всегда подтверждайте гипотезу цифрами Pss и Private_Dirty из smaps.

Что делать после диагностики (и чего не делать)

Дальше решения зависят от типа проблемы:

  • deleted files: переоткрыть файлы (релоад/сигнал) или сделать контролируемый перезапуск. Место освободится только после закрытия последнего fd.
  • memfd/shmem/anonymous mappings: это поведение приложения. Ищите настройки лимитов кэша/воркеров, утечки, регрессии в версии. Иногда помогает политика регулярных рестартов воркеров с лимитами.

Анти-практики: «убить -9 наугад» в проде без понимания роли процесса; попытки что-то «удалять» в /proc (это не обычная ФС); и игнорирование PSS в пользу RSS при большом количестве shared mappings. Если сервис должен самовосстанавливаться при утечках/зависаниях, полезно иметь мониторинг и перезапуск по правилам: см. настройку Monit для рестартов и алертов на VDS.

Мини-шпаргалка команд

# Найти удалённые, но открытые файлы (du не видит, df видит)
lsof +L1

# Посмотреть открытые fd процесса
ls -l /proc/1234/fd

# Deleted files у конкретного PID
ls -l /proc/1234/fd | grep '(deleted)'

# memfd у конкретного PID
ls -l /proc/1234/fd | grep memfd

# Быстрый итог по памяти процесса (PSS/RSS)
cat /proc/1234/smaps_rollup

# Точечный поиск memfd-маппингов
grep -n 'memfd' /proc/1234/smaps | head -n 50

Итог

Если «не сходятся» du и df — почти всегда начинайте с deleted files: lsof +L1 и проверка /proc/<pid>/fd быстро покажут виновника. Если же «исчезает» RAM или непонятно, кто создаёт давление на память, переходите на уровень маппингов: /proc/<pid>/smaps_rollup и smaps объяснят вклад через PSS и покажут, где именно живут anonymous mappings, shmem/tmpfs и участки, связанные с memfd_create. Такой подход превращает «магические» симптомы в конкретные PID и конкретные сегменты памяти, с которыми уже можно работать настройками сервиса или контролируемыми рестартами.

Поделиться статьей

Вам будет интересно

Linux PSI: как измерять pressure CPU, памяти и диска и ловить latency spikes OpenAI Статья написана AI (GPT 5)

Linux PSI: как измерять pressure CPU, памяти и диска и ловить latency spikes

Linux PSI (Pressure Stall Information) показывает, сколько времени задачи реально «ждали» CPU, память или I/O. Разберём /proc/pres ...
Kubernetes: Pod завис в ContainerCreating — диагностика CNI, FailedMount и переполнения image filesystem OpenAI Статья написана AI (GPT 5)

Kubernetes: Pod завис в ContainerCreating — диагностика CNI, FailedMount и переполнения image filesystem

Pod может долго висеть в ContainerCreating из‑за сетевого плагина (CNI not initialized), проблем со storage (FailedMount, attach t ...
Linux: что делать, если /var/log разросся и диск переполнен OpenAI Статья написана AI (GPT 5)

Linux: что делать, если /var/log разросся и диск переполнен

Если диск «внезапно» заполнился, часто виноват /var/log: разросшийся journal, сломанная ротация, дублирование логов или удалённые, ...