linux手册翻译——madvise(2)

madvise - give advice about use of memory

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

Feature Test Macro Requirements for glibc:
madvise():
    Since glibc 2.19:
        _DEFAULT_SOURCE
    Up to and including glibc 2.19:
        _BSD_SOURCE


madvise()系统掉用,用于向内核提供对于起始地址为addr,长度为length的内存空间的操作建议或者指示。在大多数情况下,此类建议的目标是提高系统或者应用程序的性能。

最初,此系统调用,仅仅支持一组“常规的(conventional)”建议值,这些建议值在各种系统中也有实现,(但是请注意,POSIX中并没有指定madvise()),后来,又添加了许多特定于Linux的建议值。

常规建议值
以下建议值允许应用程序告诉内核,它期望如何使用某些映射或者共享内存区域,以便内核可以选择适当的预读以及缓存技术。这些建议并不会影响应用程序的寓意(MADV_DONTNEED除外),但是可能会影响其性能。同样除MADV_DONTNEED之外,下列所有的建议值都与posix_madvise(3)函数类似,且具有相同的含义。

这些建议值,被指示为参数advice,参数值是以下之一:

  • MADV_NORMAL
    不做任何特殊处理,这是默认操作

  • MADV_RANDOM
    Expect page references in random order.
    期望以随机的顺序访问page,这等价于告诉内核,随机性强,局部性弱,预读机制意义不大

  • MADV_SEQUENTIAL
    Expect page references in sequential order.
    与** MADV_RANDOM**相反,期望顺序的访问page,因此内核应该积极的预读给定范围内的page,并在访问过后快速释放。

  • MADV_WILLNEED
    Expect access in the near future.
    预计不久将会被访问,因此提前预读几页是个不错的主意。

  • MADV_DONTNEED
    MADV_WILLNEED相反,预计未来长时间不会被访问,可以认为应用程序完成了对这部分内容的访问,因此内核可以释放与之相关的资源。

    成功执行MADV_DONTNEED操作之后,访问指定区域的语义将发生变化:后续访问这些页面将会成功,但是会导致从底层映射文件中重新填充内容(用于共享文件映射、共享匿名映射及shmem等)或者导致私有映射的零填充按需页面。因此此操作是直接将page给回收了,从对私有映射的处理来看,与swap还是略微不同的。

    需要注意的是,当应用于共享映射时,MADV_DONTNEED 可能不会立即释放范围内的页面。内核可以自由地选择合适的时机来释放页面。然而,调用进程的常驻集大小 (RSS) 将立即减少。

    MADV_DONTNEED 不能应用于locked pages、Huge TLB 页面或 VM_PFNMAP 页面。 (标有内核内部 VM_PFNMAP 标志的页面是不由虚拟内存子系统管理的特殊内存区域。此类页面通常由将页面映射到用户空间的设备驱动程序创建。)

Linux 特定建议值
以下是Linux下的特定建议值,在posix_madvise(3)中不存在对应项,并且在其他系统的实现中,可能有也可能没有对应项。同时,,其中一些操作会更改内存访问的语义。

  • MADV_REMOVE
    释放给定范围的页面及其关联的后备存储。这相当于在后备存储的相应字节范围内打一个洞(参见fallocate(2))。对指定范围的后续访问将看到包含0的字节。

    指定的地址范围必须是共享、可写的映射。不能应用于locked pages、Huge TLB 页面或 VM_PFNMAP 页面。

    在最初的实现中,此标志仅仅支持tmpfs(5)。从linux 3.5开始,任何支持fallocate(2) FALLOC_FL_PUNCH_HOLE 模式的文件系统也支持 MADV_REMOVE 标志。Hugetlbfs fails with the error EINVAL and other filesystems fail with the error EOPNOTSUPP.

  • MADV_DONTFORK
    在执行fork(2)后,子进程不允许使用此范围的页面。这样是为了避免COW机制导致父进程在写入页面时更改页面的物理位置。(Such page relocations cause problems for hardware that DMAs into the page.)

  • MADV_DOFORK
    撤销 MADV_DONTFORK的效果,恢复默认行为。

  • MADV_HWPOISON
    使指定范围内的页面“中毒”,即模拟硬件内存损坏的效果,访问这些页面会引起与之相同处理。此操作仅仅适用于特权(CAP_SYS_ADMIN)进程。此操作将会导致进程收到SIGBUS,并且页面被取消映射。

    此功能用于测试内存错误的处理代码;仅当内核配置为CONFIG_MEMORY_FAILURE 时才可用。

  • MADV_MERGEABLE
    为指定范围内的页面启用KSM(Kernel Samepage Merging)。内核会定期扫描那些被标记为可合并的用户内存区域,寻找具有相同的内容的页面。他们将被一个单一的具有写保护的页面取代,并且要更新此页面时发生COW操作!KSM仅仅用于合并私有匿名映射的页面。

    KSM功能适用于生成相同数据的多个实例的应用程序(例如,KVM等虚拟化系统)。KSM会消耗大量的处理能力,应该小心使用。详细可以参阅内核源文件:Documentation/admin-guide/mm/ksm.rst

    MADV_MERGEABLE 和 MADV_UNMERGEABLE 操作仅在内核配置了 CONFIG_KSM 时才可用。

  • MADV_UNMERGEABLE
    撤消先前的 MADV_MERGEABLE 操作对指定地址范围的影响;同时恢复在指定的地址范围内合并的所有页面。

  • MADV_SOFT_OFFLINE
    将指定范围内的页面软脱机。即保留指定范围内的所有页面,使其脱离正常内存管理,不再使用,而原page的内容被迁移到新的页面,对该区域的访问不受任何影响,即MADV_SOFT_OFFLINE的操作效果对进程是不可见的,并不会改变其语义。

    此功能用于测试内存错误处理代码; 仅当内核配置为 CONFIG_MEMORY_FAILURE 时才可用。

  • MADV_HUGEPAGE
    对指定范围的页面启用透明大页(THP)。目前,透明大页仅仅适用于私有匿名页。内核会定期扫描标记为大页候选的区域,然后将其替换为大页。当区域自然对齐到大页大小时,内核也会直接分配大页(参见 posix_memalign(2))。

    此功能主要针对那些映射大范围区域,且一次性访问内存大片区域的应用程序,如QEMU。大页容易导致严重的内存浪费,比如访问访问1字节内容需要映射2MB的内存页,而不是4KB的内存页!有关更多详细信息,请参阅 Linux 内核源文件 Documentation/admin-guide/mm/transhuge.rst

    大多数常见的内核配置默认提供 MADV_HUGEPAGE 样式的行为,因此通常不需要 MADV_HUGEPAGE。它主要用于嵌入式系统,其内核中默认情况下可能不会启用 MADV_HUGEPAGE 类似的行为。在此类系统上,可使用此标志来有选择地启用 THP。每当使用 MADV_HUGEPAGE 时,它应该始终位于可访问的内存区域中,开发人员需要确保在启用透明大页面时不会增加应用程序的内存占用的风险。

    MADV_HUGEPAGE 和 MADV_NOHUGEPAGE 操作仅在内核配置了 CONFIG_TRANSPARENT_HUGEPAGE 时才可用。

  • MADV_NOHUGEPAGE
    确保指定范围内的页面不会使用透明大页。

  • MADV_DONTDUMP
    从核心转储中排除指定范围的页面。这在已知大内存区域无法用于核心转储的应用程序中很有用。MADV_DONTDUMP 的效果优先于通过 /proc/[pid]/coredump_filter 文件设置的位掩码(请参阅 core(5))。注所谓核心转储,指的是在进程发生错误时,将进程地址空及其一些特定状态数据保存到磁盘文件中,以供调试使用。

  • MADV_DODUMP
    撤销MADV_DONTDUMP的使用效果。

  • MADV_FREE
    意味着,应用程序不再需要指定范围内的页面。内核因此可以释放这些页面,但不是立即释放,而是当出现内存压力时释放。这样就会出现一些特殊情况,如果在页面被释放前被写入,那么将取消释放操作,一旦页面被释放,那么后续访问将看到0填充的页面。此外当内核释放页面时,任何陈旧数据(即脏的、未写入的页面)都将丢失。但是,随后对该范围内的页面的写入将成功,然后内核将不会释放这些脏页面,因此调用者始终可以看到刚刚写入的数据。

    MADV_FREE 操作只能应用于私有匿名页面(请参阅 mmap(2))。

  • MADV_WIPEONFORK
    在fork(2)之后,子进程访问此区域内的内容,将看到0填充数据,这样做可以确保不会将敏感的数据,如PRNG seeds, cryptographic secrets等传递给子进程。

    MADV_WIPEONFORK同样只能操作私有匿名映射的页面

    MADV_WIPEONFORK设置的区域,会在子进程中保留,也就是说,子进程的子进程依然是只能看到空白页。此设置将会在execve(2) 期间被清除。

  • MADV_KEEPONFORK
    撤销MADV_WIPEONFORK的效果

  • MADV_COLD
    Deactivate a given range of pages. This will make the pages a more probable reclaim target should there be a memory pressure. This is a nondestructive operation. The advice might be ignored for some pages in the range when it is not applicable.

    可以立即为将此区域的page标记为冷页,更容易的被回收。

  • MADV_PAGEOUT
    直接回收页面,如果是匿名页,那么将会被换出,如果是文件页并且是脏页,那么会被回写。The advice might be ignored for some pages in the range when it is not applicable.


On success, madvise() returns zero. On error, it returns -1 and errno is set to indicate the error.

  • EACCES
    advice is MADV_REMOVE, but the specified address range is not a shared writable mapping.

  • EAGAIN
    A kernel resource was temporarily unavailable.

  • EBADF
    The map exists, but the area maps something that isn't a file.

  • EINVAL
    addr is not page-aligned or length is negative. addr 必须是页对其的,或者说必须是mmap的返回值!

  • EINVAL
    advice is not a valid.

  • EINVAL
    advice is MADV_DONTNEED or MADV_REMOVE and the specified address range includes locked, Huge TLB pages, or VM_PFNMAP pages.

  • EINVAL
    advice is MADV_MERGEABLE or MADV_UNMERGEABLE, but the kernel was not configured with CONFIG_KSM.

  • EINVAL
    advice is MADV_FREE or MADV_WIPEONFORK but the specified address range includes file, Huge TLB, MAP_SHARED, or VM_PFNMAP ranges.

  • EIO
    (for MADV_WILLNEED) Paging in this area would exceed the process's maximum resident set size.

  • ENOMEM
    (for MADV_WILLNEED) Not enough memory: paging in failed.

  • ENOMEM
    addresses in the specified range are not currently mapped, or are outside the address space of the process.

  • EPERM
    advice is MADV_HWPOISON, but the caller does not have the CAP_SYS_ADMIN capability.


Since Linux 3.18, support for this system call is optional, depending on the setting of the CONFIG_ADVISE_SYSCALLS configuration option.


madvise() is not specified by any standards. Versions of this system call, implementing a wide variety of advice values, exist on many other implementations. Other implementations typically implement at least the flags listed above under Conventional advice flags, albeit with some variation in semantics.

POSIX.1-2001 describes posix_madvise(3) with constants POSIX_MADV_NORMAL, POSIX_MADV_RANDOM, POSIX_MADV_SEQUENTIAL, POSIX_MADV_WILLNEED, and POSIX_MADV_DONTNEED, and so on, with behavior close to the similarly named flags listed above.


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

你可能感兴趣的:(linux手册翻译——madvise(2))