MADVISE(2)

ИМЯ
madvise - отсылает предложения по использованию памяти

ОБЗОР
#include <sys/mman.h>

int madvise(void *addr, size_t length, int advice);

Требования макроса тестирования свойств для glibc (смотрите feature_test_macros(7)):

madvise():
    Начиная с glibc 2.19:
        _DEFAULT_SOURCE
    Начиная с glibc 2.19:
        _BSD_SOURCE

ОПИСАНИЕ
Системный вызов madvise() используется, чтобы дать совет или указать направление ядру о диапазоне адресов, начинающемся с адреса addr и имеющем размер length байт. В большинстве случаев, целью такого совета является повышение производительности системы или приложения.

Первоначально, системный вызов поддерживал набор «стандартных» значений advice, которые также доступны и в некоторых других реализациях (однако отметим, что madvise() отсутствует в POSIX). В последствии было добавлено несколько значений advice, имеющихся только в Linux.

  Стандартные значения предложений
Значения advice, перечисленные далее, позволяют приложению указать ядру как оно будет использовать некоторые отображённые или общие области памяти, чтобы ядро могло выбрать подходящие методы упреждающего чтения и кэширования. Эти значения advice не влияют на семантику приложения (за исключением MADV_DONTNEED), но могут повлиять на его производительность. Все перечисленные здесь значения advice имеют аналоги в определённой POSIX функции posix_madvise(3) и имеют тот же смысл, за исключением MADV_DONTNEED.

В advice помещается нужное предложения, одно из:

MADV_NORMAL
    Нет никаких специальных указаний. Используется по умолчанию.

MADV_RANDOM
    Ожидать обращение к страницам в случайном порядке (здесь упреждающее чтение может быть менее эффективным).

MADV_SEQUENTIAL
    Ожидать последовательного обращения к страницам (здесь к страницам в заданном диапазоне можно применить агрессивное упреждающее чтение и быстро высвободить их сразу после доступа).

MADV_WILLNEED
    Ожидать доступа в ближайшем будущем (здесь можно применить упреждающее чтение нескольких страниц).

MADV_DONTNEED
    В ближайшем будущем не ожидается доступ (в настоящее время приложение закончило работу с данным диапазоном, поэтому ядро может освободить ресурсы, связанные с приложением).

    После успешного выполнения операции MADV_DONTNEED семантика доступа к памяти в заданной области изменяется: последующий доступ к страницам в области будет успешным, но будет приводить к или повторному заполнению памяти актуальным содержимым из нижележащего отображённого файла (для общих отображений файла, общих анонимных отображений и методов на основе shmem, таких как сегментов общей памяти System V) или к заполнению нулями страниц по требованию у частных анонимных отображений.

    Заметим, что при применении к общим отображениям операция MADV_DONTNEED может не приводить к немедленному освобождению страниц области. Ядро может задержать освобождение до подходящего момента. Однако размер постоянно занимаемой памяти (RSS) вызывающего процесса будет сокращён сразу же.

    Операция MADV_DONTNEED не может применяться к заблокированным страницам, страницам Huge TLB или страницам VM_PFNMAP (страницы, помеченные внутренним флагом ядра VM_PFNMAP представляют собой специальные области памяти, которые не управляются из подсистемы виртуальной памяти; обычно, эти страницы создаются драйверами устройств, которые отображают страницы в пользовательское пространство).

  Значения предложений, имеющиеся только в Linux
Следующие значения advice имеются только в Linux и не имеют аналога в определённой POSIX функции posix_madvise(3), а также могут не иметь аналога и в других реализациях интерфейса madvise(). Заметим, что некоторые из этих операций изменяют семантику доступа к памяти.

MADV_REMOVE (начиная с Linux 2.6.16)
    Освободить указанный диапазон страниц и связанные с ним хранилища. Эквивалентен пробивке отверстия в соответствующем диапазоне байт хранилища (смотрите fallocate(2)). Последующий доступ к указанному адресному диапазону будет возвращать байты с нулями.

    Указываемый адресный диапазон должен быть общим и доступным на запись отображением. Этот флаг не может применять к заблокированным страницам, страницам Huge TLB или страницам VM_PFNMAP.

    В первоначальной реализации MADV_REMOVE поддерживался только в tmpfs(5), но начиная с Linux 3.5 все файловые системы, поддерживающие fallocate(2) с режимом FALLOC_FL_PUNCH_HOLE, также поддерживают MADV_REMOVE. Hugetlbfs возвращает ошибку EINVAL, а другие файловые системы возвращают ошибку EOPNOTSUPP.

MADV_DONTFORK (начиная с Linux 2.6.16)
    Сделать недоступными страницы в указанном диапазоне для потомка после fork(2). Это полезно для предотвращения изменения физического расположения страницы копирования-при-записи, если родитель будет изменять её после fork(2) (перемещение таких страниц вызывает проблемы для оборудования, обращающегося к страницам через DMA).

MADV_DOFORK (начиная с Linux 2.6.16)
    Отменить действие MADV_DONTFORK, восстановить поведение по умолчанию, в силу чего происходит наследование отображения после fork(2).

MADV_HWPOISON (начиная с Linux 2.6.32)
    Испортить страницы в диапазоне, заданном addr и length, и обрабатывать последующие ссылки на эти страницы как при аппаратном повреждении памяти. Данная операция доступна только для привилегированных (CAP_SYS_ADMIN) процессов. Она может привести к тому, что вызывающий процесс получит SIGBUS и отображение страницы удалится.

    Это свойство предназначено для тестирования кода обработки ошибок памяти; оно доступно только, если ядро было собрано с параметром CONFIG_MEMORY_FAILURE.

MADV_MERGEABLE (начиная с Linux 2.6.32)
    Включает слияние одинаковых страниц ядра (Kernel Samepage Merging, KSM) для страниц в диапазоне, указанном addr и length. Ядро периодически сканирует области пользовательской памяти, которые были помечены для слияния, разыскивая станицы с одинаковым содержимым. Такие страницы заменяются единственной страницей, защищённой от записи (которая автоматически копируется, если позднее процесс захочет изменить содержимое страницы). При KSM слияние выполняется только для частных анонимных страниц (смотрите mmap(2)).

    Возможность KSM предназначена для приложений, которые генерируют много экземпляров одинаковых данных (например, для систем виртуализации, таких как KVM). Эта возможность может нагрузить процессор; используйте осторожно. Дополнительную информацию можно найти в файле исходного кода ядра Documentation/admin-guide/mm/ksm.rst.

    Операции MADV_MERGEABLE и MADV_UNMERGEABLE доступны только, если ядро собрано с параметром CONFIG_KSM.

MADV_UNMERGEABLE (начиная с Linux 2.6.32)
    Отменить действие ранее применённой операции MADV_MERGEABLE для указанного диапазона; KSM разделяет ранее объединённые страницы в диапазоне, заданном addr и length.

MADV_SOFT_OFFLINE (начиная с Linux 2.6.33)
    Программно отключить страницы в диапазоне, указанном addr и length. Память каждой страницы в указанном диапазоне сохраняется (т. е., при следующем доступе будет выдано то же содержимое, но в новых физических границах страницы) и первоначальная страница отключается (т. е., больше не используется и не участвует при обычном управлении памятью). Эффект операции MADV_SOFT_OFFLINE обычно незаметен (т. е., не изменяет семантику) для вызывающего процесса.

    Это свойство предназначено для тестирования кода обработки ошибок памяти; оно доступно только, если ядро было собрано с параметром CONFIG_MEMORY_FAILURE.

MADV_HUGEPAGE (начиная с Linux 2.6.38)
    Включает прозрачность огромных страниц (Transparent Huge Pages, THP) для страниц в диапазоне, указанном addr и length. В настоящий момент, THP работает только для закрытых (private) анонимных страниц (смотрите mmap(2)). Ядро будет периодически сканировать области, помеченные как кандидаты в огромные страницы, для замены их огромными страницами. Ядро также будет непосредственно выделять огромные страницы, если область выравнена на аппаратный (naturally) размер огромной страницы при создании (смотрите posix_memalign(2)).

    В основном, эта возможность предназначена для приложений, которые используют большие отображения данных и доступ к большим областям этой памяти за один приём (например, системы виртуализации, такие как QEMU). С её помощью можно очень легко занять память (например, на 2 МБ отображение, из которого нужен только 1 байт, будет потрачено 2 МБ реальной памяти вместо одной 4 КБ страницы). Дополнительную информацию смотрите в файле Documentation/admin-guide/mm/transhuge.rst из исходного кода ядра.

    Операции MADV_HUGEPAGE и MADV_NOHUGEPAGE доступны только, если ядро собрано с параметром CONFIG_TRANSPARENT_HUGEPAGE.

MADV_NOHUGEPAGE (начиная с Linux 2.6.38)
    Проверить, что память адресного пространства, указанного в addr и length, не будет свёрнута в огромные страницы.

MADV_DONTDUMP (начиная с Linux 3.4)
    Исключить из дампа памяти страницы диапазона, задаваемого значениями addr и length. Это полезно в приложениях, которые занимают большие области в памяти, про которые известно, что они ничем не помогут будучи в дампе памяти. Действие MADV_DONTDUMP имеет преимущество над битовой маской, которая устанавливается в файле /proc/[pid]/coredump_filter (смотрите core(5)).

MADV_DODUMP (начиная с Linux 3.4)
    Отменяет действие, установленное ранее MADV_DONTDUMP.

MADV_FREE (начиная с Linux 4.5)
    Приложению больше не требуются страницы в диапазоне, задаваемом addr и len, поэтому ядро может освободить эти страницы, но освобождение может быть отложено до тех пор, пока не понадобится память. Для каждой страницы, помеченной как свободная, но ещё не освобождённая, операция освобождения будет отменена, если вызывающий выполнит запись в эту страницу. После успешного выполнения операции MADV_FREE все повисшие данные (т. е., изменённые (dirty) и не записанные страницы) будут потеряны в момент освобождения страниц ядром. Однако последующая запись в страницы в этом диапазоне будет успешной и поэтому ядро не сможет освободить эти изменённые страницы и вызывающий всегда может видеть только что записанные данные. Если последующей записи не было, то ядро может освободить страницы в любой момент. После освобождения страниц диапазона при последующем доступе вызывающий может видеть страницы заполненные нулями по требованию.

    Операция MADV_FREE может применяться только при частным анонимным страницам (смотрите mmap(2)). В Linux до версии 4.12 страницы задаваемого диапазона в системе без подкачки освобождаются сразу, независимо от необходимости в памяти.

MADV_WIPEONFORK (начиная с Linux 4.14)
    Выдать дочернему процессу заполненную нулями память в этом диапазоне после fork(2). Это позволяет при ветвлении (forking) серверов стереть важные данные процесса (например, начальные значения PRNG, данные шифрования и т. п.) у дочерних процессов.

    Операция MADV_WIPEONFORK применима только к частным анонимным страницам (смотрите mmap(2)).

    В потомке, созданном fork(2), значение MADV_WIPEONFORK остаётся у указанного адресного диапазона. Это значение стирается при execve(2).

MADV_KEEPONFORK (начиная с Linux 4.14)
    Отменяет действие, установленное ранее MADV_WIPEONFORK.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При нормальном завершении работы madvise() возвращает ноль. При ошибке возвращается -1, а переменной errno присваивается соответствующее значение.

ОШИБКИ

EACCES
    В advice указан MADV_REMOVE, но описанный диапазон адресов не является общей памятью с разрешением на записи

EAGAIN
    Ресурс ядра временно недоступен.

EBADF
    Отображение существует, то область отображения не является файловой.

EINVAL
    Значение параметра addr не выровнено по границе страницы или параметр length содержит отрицательное число.

EINVAL
    Значение advice недопустимо.

EINVAL
    Значение advice равно MADV_DONTNEED или MADV_REMOVE, а указанный адресный диапазон включает заблокированные, Huge TLB или VM_PFNMAP страницы.

EINVAL
    Значение advice равно MADV_MERGEABLE или MADV_UNMERGEABLE, но ядро было собрано без параметра CONFIG_KSM.

EINVAL
    Значение advice равно MADV_FREE или MADV_WIPEONFORK, но в указанном адресном диапазоне содержится файл, Huge TLB, диапазоны MAP_SHARED или VM_PFNMAP.

EIO (для MADV_WILLNEED) Выделение страницы в данной области превысило бы максимальный размер постоянно находящихся в памяти страниц для процесса (rss).

ENOMEM
    (для MADV_WILLNEED) Недостаточно памяти: не удалось выделить страницу

ENOMEM
    Адреса в указанном диапазоне в настоящее время не отображены, или лежит вне адресного пространства процесса.

EPERM
    В переменной advice содержится MADV_HWPOISON, но вызывающий не имеет мандата CAP_SYS_ADMIN.

ВЕРСИИ
Начиная с Linux 3.18 поддержка данного системного вызова необязательна, она зависит от того, собрано ли ядро с параметром CONFIG_ADVISE_SYSCALLS.

СООТВЕТСТВИЕ СТАНДАРТАМ
Вызов madvise() не включён ни в один стандарт. Версии этого системного вызова, реализующие широкий набор значений advice, существуют во многих других системах. В них, обычно, реализуются, как минимум, флаги перечисленные в Стандартные значения предложений, хотя и с некоторыми различиями в семантике.

В POSIX-2001 описана функция posix_madvise(3) с константами POSIX_MADV_NORMAL, POSIX_MADV_RANDOM, POSIX_MADV_SEQUENTIAL, POSIX_MADV_WILLNEED и POSIX_MADV_DONTNEED, и т. п., реализующая поведение близкое к флагам с именами, перечисленным выше.

ЗАМЕЧАНИЯ

  Замечания, касающиеся Linux
Для реализации Linux требуется, чтобы адрес addr был выровнен на границу страницы, а значение length может быть нулевым. Если какие-то части указанного адресного диапазона не отображены, то версия Linux madvise() игнорирует их и вызов применяется к оставшейся области (но возвращается значение ENOMEM, как и должно).

СМОТРИТЕ ТАКЖЕ
getrlimit(2), mincore(2), mmap(2), mprotect(2), msync(2), munmap(2), prctl(2), posix_madvise(3), core(5)