备注

Linux notes

Linux实现要求地址addr进行页面对齐,并允许长度为零。如果指定地址范围的某些部分未映射,则Linux版本madvise()会将其忽略,并将调用应用于其余部分(但应从系统调用中返回ENOMEM)。

遵循规范

madvise()没有任何标准指定。实现许多建议值的此系统调用的版本存在于许多其他实现中。其他实现通常至少实现上述常规建议标志下列出的标志,尽管语义有所不同。

POSIX.1-2001使用常量POSIX_MADV_NORMALPOSIX_MADV_RANDOMPOSIX_MADV_SEQUENTIAL,POSIX_MADV_WILLNEED和POSIX_MADV_DONTNEED等常量来描述posix_madvise(3),其行为接近上面列出的类似名称的标志。

错误说明

EACCES
建议为MADV_REMOVE,但指定的地址范围不是共享的可写映射。
EAGAIN
内核资源暂时不可用。
EBADF
该地图存在,但是该区域映射的不是文件。
EINVAL
addr不是页面对齐的或length为负。
EINVAL
咨询无效。
EINVAL
建议为MADV_DONTNEED或MADV_REMOVE,并且指定的地址范围包括锁定的,巨大的TLB页面或VM_PFNMAP页面。
EINVAL
建议使用MADV_MERGEABLE或MADV_UNMERGEABLE,但内核未配置CONFIG_KSM。
EINVAL
建议为MADV_FREE或MADV_WIPEONFORK,但指定的地址范围包括文件,巨大TLB,MAP_SHARED或VM_PFNMAP范围。
EIO
(对于MADV_WILLNEED)此区域中的分页将超出进程的最大常驻集大小。
ENOMEM
(对于MADV_WILLNEED)内存不足:分页失败。
ENOMEM
指定范围内的地址当前未映射,或者在进程的地址空间之外。
EPERM
建议为MADV_HWPOISON,但呼叫者没有CAP_SYS_ADMIN功能。

语法

#包括

int madvise(无效* addr,size_t长度,int通知);

glibc的功能测试宏要求(请参阅feature_test_macros(7)):

madvise():

Since glibc 2.19:
_DEFAULT_SOURCE
Up to and including glibc 2.19:
_BSD_SOURCE

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/

返回值

成功时,madvise()返回零。错误时,它返回-1并正确设置了errno。

名称

madvise-提供有关内存使用的建议

MADVISE - Linux手册页

Linux程序员手册 第2部分
更新日期: 2020-04-11

另外参见

getrlimit(2),mincore(2),mmap(2),mprotect(2),msync(2),munmap(2),prctl(2),posix_madvise(3),core(5)

说明

madvise()系统调用用于向内核提供有关地址范围的建议或指导,这些地址范围始于地址addr且具有大小长度字节。在大多数情况下,此类建议的目的是提高系统或应用程序的性能。

最初,系统调用支持一组"常规"建议值,这些建议值也可以在其他几种实现中使用。 (但是请注意,在POSIX中未指定madvise()。)随后,添加了许多特定于Linux的建议值。

Conventional advice values

下面列出的建议值使应用程序可以告诉内核它希望如何使用某些映射或共享的内存区域,以便内核可以选择适当的预读和缓存技术。这些建议值不影响应用程序的语义(对于MADV_DONTNEED除外),但可能会影响其性能。此处列出的所有建议值在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无法应用于锁定的页面,巨大的TLB页面或VM_PFNMAP页面。 (标记有内核内部VM_PFNMAP标志的页面是不由虚拟内存子系统管理的特殊内存区域。此类页面通常由将页面映射到用户空间的设备驱动程序创建。)

Linux-specific advice values

以下特定于Linux的建议值在POSIX指定的posix_madvise(3)中没有对应项,在madvise()接口中的对应项可能有也可能没有其他实现上的对应项。请注意,其中一些操作会更改内存访问的语义。

MADV_REMOVE(since Linux 2.6.16)
释放给定范围的页面及其关联的后备存储。这等效于在后备存储的相应字节范围内打洞(请参见fallocate(2))。在指定地址范围内的后续访问将看到包含零的字节。
指定的地址范围必须映射为共享且可写。此标志不能应用于锁定的页面,巨大的TLB页面或VM_PFNMAP页面。
在最初的实现中,仅支持tmpfs(5)MADV_REMOVE;但是从Linux 3.5开始,任何支持fallocate(2)FALLOC_FL_PUNCH_HOLE模式的文件系统也都支持MADV_REMOVE。 Hugetlbfs失败,错误为EINVAL,其他文件系统失败,错误为EOPNOTSUPP。
MADV_DONTFORK(since Linux 2.6.16)
fork(2)之后,不要让该范围的页面可供孩子使用。如果父项在fork(2)之后写入页面,则这对于防止写时复制语义更改页面的物理位置很有用。 (此类页面重定位会导致将DMA插入页面的硬件出现问题。)
MADV_DOFORK(since Linux 2.6.16)
撤消MADV_DONTFORK的效果,恢复默认行为,从而跨fork(2)继承映射。
MADV_HWPOISON(since Linux 2.6.32)
毒化由addr和length指定的范围内的页面,并处理对这些页面的后续引用,例如硬件内存损坏。此操作仅适用于特权(CAP_SYS_ADMIN)进程。此操作可能导致调用过程接收到SIGBUS,并且页面未映射。
此功能旨在测试内存错误处理代码。仅当内核配置有CONFIG_MEMORY_FAILURE时,此选项才可用。
MADV_MERGEABLE(since Linux 2.6.32)
为地址由addr和length指定的范围内的页面启用内核同一页面合并(KSM)。内核会定期扫描那些已标记为可合并的用户内存区域,以查找内容相同的页面。这些将被单个写保护页面替换(如果以后某个进程想要更新页面内容,则会自动复制该页面)。 KSM仅合并私有匿名页面(请参阅mmap(2))。
KSM功能适用于生成许多相同数据实例的应用程序(例如,虚拟化系统,例如KVM)。它会消耗大量的处理能力;小心使用。有关更多详细信息,请参见Linux内核源文件Documentation / admin-guide / mm / ksm.rst。
仅当内核使用CONFIG_KSM配置时,MADV_MERGEABLE和MADV_UNMERGEABLE操作才可用。
MADV_UNMERGEABLE(since Linux 2.6.32)
撤消先前的MADV_MERGEABLE操作对指定地址范围的影响; KSM会在addr和length指定的地址范围内取消合并的所有页面。
MADV_SOFT_OFFLINE(since Linux 2.6.33)
使地址由addr和length指定的范围内的页面软脱机。保留指定范围内每个页面的内存(即,下次访问时,相同的内容将可见,但是在新的物理页面框架中),并且原始页面已脱机(即,不再使用并取出)正常的内存管理)。 MADV_SOFT_OFFLINE操作的效果对于调用过程是不可见的(即,不改变其语义)。
此功能旨在测试内存错误处理代码。仅当内核配置有CONFIG_MEMORY_FAILURE时,此选项才可用。
MADV_HUGEPAGE(since Linux 2.6.38)
在地址和长度指定的范围内的页面上启用透明大页面(THP)。当前,"透明大页面"仅与私有匿名页面一起使用(请参阅mmap(2))。内核将定期扫描标记为大页面候选者的区域,以将其替换为大页面。当区域自然地与大页面大小对齐时,内核还将直接分配大页面(请参阅posix_memalign(2))。
此功能主要针对使用大型数据映射并一次访问该内存较大区域的应用程序(例如,虚拟化系统,例如QEMU)。它很容易浪费内存(例如,仅访问1个字节的2 MB映射将导致2 MB的有线内存,而不是一个4 KB的页面)。有关更多详细信息,请参见Linux内核源文件Documentation / admin-guide / mm / transhuge.rst。
默认情况下,大多数常见的内核配置都提供MADV_HUGEPAGE样式的行为,因此,通常不需要MADV_HUGEPAGE。它主要用于嵌入式系统,其中默认情况下可能未在内核中启用MADV_HUGEPAGE样式的行为。在此类系统上,可以使用此标志来选择性地启用THP。每当使用MADV_HUGEPAGE时,它都应该始终位于具有开发模式事先知道不会启用增加的透明大页的应用程序的内存占用的风险的访问模式的内存区域中。
仅当内核配置了CONFIG_TRANSPARENT_HUGEPAGE时,MADV_HUGEPAGE和MADV_NOHUGEPAGE操作才可用。
MADV_NOHUGEPAGE(since Linux 2.6.38)
确保由addr和length指定的地址范围内的内存不会被透明的大页支持。
MADV_DONTDUMP(since Linux 3.4)
从核心转储中排除由addr和length指定的范围内的那些页面。这在内存很大的应用程序中很有用,这些应用程序在核心转储中不起作用。 MADV_DONTDUMP的效果优先于通过/ proc / [pid] / coredump_filter文件设置的位掩码(请参阅core(5))。
MADV_DODUMP(since Linux 3.4)
撤消较早的MADV_DONTDUMP的效果。
MADV_FREE(since Linux 4.5)
该应用程序不再需要由addr和len指定的范围内的页面。内核因此可以释放这些页面,但是释放可以延迟到出现内存压力为止。对于已标记为已释放但尚未释放的每个页面,如果调用者写入该页面,则释放操作将被取消。成功执行MADV_FREE操作后,内核释放页面时,所有过时的数据(即脏的,未写入的页面)都将丢失。但是,随后对该范围内的页面的写操作将成功,然后内核无法释放那些脏页,从而使调用者始终只能看到已写的数据。如果没有后续写入,则内核可以随时释放页面。释放范围内的页面后,调用者将在随后的页面引用中看到按需填充零页面。
MADV_FREE操作只能应用于私有匿名页面(请参阅mmap(2))。在4.12之前的Linux中,在无交换系统上释放页面时,将立即释放给定范围内的页面,而不考虑内存压力。
MADV_WIPEONFORK(since Linux 4.14)
fork(2)之后,在此范围内为子进程提供零填充内存。这对于分叉服务器很有用,以确保不将敏感的按进程数据(例如PRNG种子,加密机密等)传递给子进程。
MADV_WIPEONFORK操作只能应用于私有匿名页面(请参阅mmap(2))。
fork(2)创建的子级中,MADV_WIPEONFORK设置保留在指定地址范围内。在execve(2)期间清除此设置。
MADV_KEEPONFORK(since Linux 4.14)
撤消较早版本的MADV_WIPEONFORK的效果。

版本

从Linux 3.18开始,对此系统调用的支持是可选的,具体取决于CONFIG_ADVISE_SYSCALLS配置选项的设置。

日期:2019-08-20 17:58:58 来源:oir作者:oir