Когда процесс работает с большой областью памяти, ядро не всегда знает, как именно приложение будет обращаться к этим страницам.
Linux предоставляет
madvise() - системный вызов, через который процесс может сообщить ядру предполагаемый характер использования памяти.Это особенно интересно для
mmap() и больших memory-mapped файлов.▪️Последовательный доступ
Если программа собирается читать память последовательно:
madvise(addr, length, MADV_SEQUENTIAL);
ядро получает подсказку, что страницы будут использоваться примерно по порядку.
Это позволяет иначе управлять page cache и упреждающим чтением.
Например, обработчик большого файла может пройти по нему от начала до конца вместо случайных обращений.
▪️Случайный доступ
Для случайного доступа есть:
madvise(addr, length, MADV_RANDOM);
Если приложение читает страницы в произвольном порядке, агрессивное read-ahead может оказаться бесполезным.
Подсказка позволяет ядру учитывать такой сценарий.
▪️Можно сообщить, что страницы больше не нужны
Особенно интересен:
madvise(addr, length, MADV_DONTNEED);
Процесс говорит ядру, что содержимое этой области ему сейчас не требуется.
Для анонимной памяти это может позволить освободить физические страницы. Для файлового отображения поведение связано с отображёнными страницами и page cache.
Важно: это не то же самое, что
free().Виртуальный адрес всё ещё может оставаться отображённым, но физические страницы могут быть освобождены и восстановлены при следующем обращении.
▪️Есть и подсказка
WILLNEEDmadvise(addr, length, MADV_WILLNEED);
Она сообщает ядру, что страницы, вероятно, скоро понадобятся.
Это может помочь подготовить данные заранее, например перед обработкой большого memory-mapped файла.
Но
madvise() именно подсказывает, а не заставляет ядро выполнить конкретную стратегию.▪️Практический сценарий
Представим программу, которая через
mmap() обрабатывает несколько гигабайт файла строго последовательно.Вместо случайного поведения с page cache она может сделать:
void *p = mmap(NULL, size,
PROT_READ,
MAP_PRIVATE,
fd, 0);
madvise(p, size, MADV_SEQUENTIAL);
Теперь приложение явно сообщает ядру характер будущего доступа.
А когда большой участок больше не нужен:
madvise(p, size, MADV_DONTNEED);
Это может уменьшить давление на память, не требуя немедленно уничтожать само отображение.
▪️Важный нюанс
madvise() не является универсальной кнопкой «ускорить память».Эффект зависит от конкретного флага, типа mapping, версии ядра и сценария доступа.
И особенно важно не путать
MADV_DONTNEED с гарантированным физическим освобождением каждой страницы: это рекомендация ядру о том, что содержимое региона можно считать ненужным.То есть
madvise() - это интерфейс, через который userspace сообщает kernel memory manager: «я примерно знаю, что собираюсь делать с этой памятью».BashTex 📱 #bash #utils