madvise - give advice about use of memory
#include <sys/mman.h>
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()系統(tǒng)掉用,用于向內(nèi)核提供對于起始地址為addr,長度為length的內(nèi)存空間的操作建議或者指示。在大多數(shù)情況下,此類建議的目標是提高系統(tǒng)或者應用程序的性能。
最初,此系統(tǒng)調(diào)用,僅僅支持一組“常規(guī)的(conventional)”建議值,這些建議值在各種系統(tǒng)中也有實現(xiàn),(但是請注意,POSIX中并沒有指定madvise()),后來,又添加了許多特定于Linux的建議值。
常規(guī)建議值
以下建議值允許應用程序告訴內(nèi)核,它期望如何使用某些映射或者共享內(nèi)存區(qū)域,以便內(nèi)核可以選擇適當?shù)念A讀以及緩存技術(shù)。這些建議并不會影響應用程序的寓意(MADV_DONTNEED除外),但是可能會影響其性能。同樣除MADV_DONTNEED之外,下列所有的建議值都與posix_madvise(3)函數(shù)類似,且具有相同的含義。
這些建議值,被指示為參數(shù)advice,參數(shù)值是以下之一:
MADV_NORMAL
不做任何特殊處理,這是默認操作MADV_RANDOM
Expect page references in random order.
期望以隨機的順序訪問page,這等價于告訴內(nèi)核,隨機性強,局部性弱,預讀機制意義不大MADV_SEQUENTIAL
Expect page references in sequential order.
與** MADV_RANDOM**相反,期望順序的訪問page,因此內(nèi)核應該積極的預讀給定范圍內(nèi)的page,并在訪問過后快速釋放。MADV_WILLNEED
Expect access in the near future.
預計不久將會被訪問,因此提前預讀幾頁是個不錯的主意。-
MADV_DONTNEED
與MADV_WILLNEED相反,預計未來長時間不會被訪問,可以認為應用程序完成了對這部分內(nèi)容的訪問,因此內(nèi)核可以釋放與之相關(guān)的資源。成功執(zhí)行MADV_DONTNEED操作之后,訪問指定區(qū)域的語義將發(fā)生變化:后續(xù)訪問這些頁面將會成功,但是會導致從底層映射文件中重新填充內(nèi)容(用于共享文件映射、共享匿名映射及shmem等)或者導致私有映射的零填充按需頁面。因此此操作是直接將page給回收了,從對私有映射的處理來看,與swap還是略微不同的。
需要注意的是,當應用于共享映射時,MADV_DONTNEED 可能不會立即釋放范圍內(nèi)的頁面。內(nèi)核可以自由地選擇合適的時機來釋放頁面。然而,調(diào)用進程的常駐集大小 (RSS) 將立即減少。
MADV_DONTNEED 不能應用于locked pages、Huge TLB 頁面或 VM_PFNMAP 頁面。 (標有內(nèi)核內(nèi)部 VM_PFNMAP 標志的頁面是不由虛擬內(nèi)存子系統(tǒng)管理的特殊內(nèi)存區(qū)域。此類頁面通常由將頁面映射到用戶空間的設(shè)備驅(qū)動程序創(chuàng)建。)
Linux 特定建議值
以下是Linux下的特定建議值,在posix_madvise(3)中不存在對應項,并且在其他系統(tǒng)的實現(xiàn)中,可能有也可能沒有對應項。同時,,其中一些操作會更改內(nèi)存訪問的語義。
-
MADV_REMOVE
釋放給定范圍的頁面及其關(guān)聯(lián)的后備存儲。這相當于在后備存儲的相應字節(jié)范圍內(nèi)打一個洞(參見fallocate(2))。對指定范圍的后續(xù)訪問將看到包含0的字節(jié)。指定的地址范圍必須是共享、可寫的映射。不能應用于locked pages、Huge TLB 頁面或 VM_PFNMAP 頁面。
在最初的實現(xiàn)中,此標志僅僅支持tmpfs(5)。從linux 3.5開始,任何支持fallocate(2) FALLOC_FL_PUNCH_HOLE 模式的文件系統(tǒng)也支持 MADV_REMOVE 標志。Hugetlbfs fails with the error EINVAL and other filesystems fail with the error EOPNOTSUPP.
MADV_DONTFORK
在執(zhí)行fork(2)后,子進程不允許使用此范圍的頁面。這樣是為了避免COW機制導致父進程在寫入頁面時更改頁面的物理位置。(Such page relocations cause problems for hardware that DMAs into the page.)MADV_DOFORK
撤銷 MADV_DONTFORK的效果,恢復默認行為。-
MADV_HWPOISON
使指定范圍內(nèi)的頁面“中毒”,即模擬硬件內(nèi)存損壞的效果,訪問這些頁面會引起與之相同處理。此操作僅僅適用于特權(quán)(CAP_SYS_ADMIN)進程。此操作將會導致進程收到SIGBUS,并且頁面被取消映射。此功能用于測試內(nèi)存錯誤的處理代碼;僅當內(nèi)核配置為CONFIG_MEMORY_FAILURE 時才可用。
-
MADV_MERGEABLE
為指定范圍內(nèi)的頁面啟用KSM(Kernel Samepage Merging)。內(nèi)核會定期掃描那些被標記為可合并的用戶內(nèi)存區(qū)域,尋找具有相同的內(nèi)容的頁面。他們將被一個單一的具有寫保護的頁面取代,并且要更新此頁面時發(fā)生COW操作!KSM僅僅用于合并私有匿名映射的頁面。KSM功能適用于生成相同數(shù)據(jù)的多個實例的應用程序(例如,KVM等虛擬化系統(tǒng))。KSM會消耗大量的處理能力,應該小心使用。詳細可以參閱內(nèi)核源文件:Documentation/admin-guide/mm/ksm.rst
MADV_MERGEABLE 和 MADV_UNMERGEABLE 操作僅在內(nèi)核配置了 CONFIG_KSM 時才可用。
MADV_UNMERGEABLE
撤消先前的 MADV_MERGEABLE 操作對指定地址范圍的影響;同時恢復在指定的地址范圍內(nèi)合并的所有頁面。-
MADV_SOFT_OFFLINE
將指定范圍內(nèi)的頁面軟脫機。即保留指定范圍內(nèi)的所有頁面,使其脫離正常內(nèi)存管理,不再使用,而原page的內(nèi)容被遷移到新的頁面,對該區(qū)域的訪問不受任何影響,即MADV_SOFT_OFFLINE的操作效果對進程是不可見的,并不會改變其語義。此功能用于測試內(nèi)存錯誤處理代碼; 僅當內(nèi)核配置為 CONFIG_MEMORY_FAILURE 時才可用。
-
MADV_HUGEPAGE
對指定范圍的頁面啟用透明大頁(THP)。目前,透明大頁僅僅適用于私有匿名頁。內(nèi)核會定期掃描標記為大頁候選的區(qū)域,然后將其替換為大頁。當區(qū)域自然對齊到大頁大小時,內(nèi)核也會直接分配大頁(參見 posix_memalign(2))。此功能主要針對那些映射大范圍區(qū)域,且一次性訪問內(nèi)存大片區(qū)域的應用程序,如QEMU。大頁容易導致嚴重的內(nèi)存浪費,比如訪問訪問1字節(jié)內(nèi)容需要映射2MB的內(nèi)存頁,而不是4KB的內(nèi)存頁!有關(guān)更多詳細信息,請參閱 Linux 內(nèi)核源文件 Documentation/admin-guide/mm/transhuge.rst
大多數(shù)常見的內(nèi)核配置默認提供 MADV_HUGEPAGE 樣式的行為,因此通常不需要 MADV_HUGEPAGE。它主要用于嵌入式系統(tǒng),其內(nèi)核中默認情況下可能不會啟用 MADV_HUGEPAGE 類似的行為。在此類系統(tǒng)上,可使用此標志來有選擇地啟用 THP。每當使用 MADV_HUGEPAGE 時,它應該始終位于可訪問的內(nèi)存區(qū)域中,開發(fā)人員需要確保在啟用透明大頁面時不會增加應用程序的內(nèi)存占用的風險。
MADV_HUGEPAGE 和 MADV_NOHUGEPAGE 操作僅在內(nèi)核配置了 CONFIG_TRANSPARENT_HUGEPAGE 時才可用。
MADV_NOHUGEPAGE
確保指定范圍內(nèi)的頁面不會使用透明大頁。MADV_DONTDUMP
從核心轉(zhuǎn)儲中排除指定范圍的頁面。這在已知大內(nèi)存區(qū)域無法用于核心轉(zhuǎn)儲的應用程序中很有用。MADV_DONTDUMP 的效果優(yōu)先于通過 /proc/[pid]/coredump_filter 文件設(shè)置的位掩碼(請參閱 core(5))。注所謂核心轉(zhuǎn)儲,指的是在進程發(fā)生錯誤時,將進程地址空及其一些特定狀態(tài)數(shù)據(jù)保存到磁盤文件中,以供調(diào)試使用。MADV_DODUMP
撤銷MADV_DONTDUMP的使用效果。-
MADV_FREE
意味著,應用程序不再需要指定范圍內(nèi)的頁面。內(nèi)核因此可以釋放這些頁面,但不是立即釋放,而是當出現(xiàn)內(nèi)存壓力時釋放。這樣就會出現(xiàn)一些特殊情況,如果在頁面被釋放前被寫入,那么將取消釋放操作,一旦頁面被釋放,那么后續(xù)訪問將看到0填充的頁面。此外當內(nèi)核釋放頁面時,任何陳舊數(shù)據(jù)(即臟的、未寫入的頁面)都將丟失。但是,隨后對該范圍內(nèi)的頁面的寫入將成功,然后內(nèi)核將不會釋放這些臟頁面,因此調(diào)用者始終可以看到剛剛寫入的數(shù)據(jù)。MADV_FREE 操作只能應用于私有匿名頁面(請參閱 mmap(2))。
-
MADV_WIPEONFORK
在fork(2)之后,子進程訪問此區(qū)域內(nèi)的內(nèi)容,將看到0填充數(shù)據(jù),這樣做可以確保不會將敏感的數(shù)據(jù),如PRNG seeds, cryptographic secrets等傳遞給子進程。MADV_WIPEONFORK同樣只能操作私有匿名映射的頁面
MADV_WIPEONFORK設(shè)置的區(qū)域,會在子進程中保留,也就是說,子進程的子進程依然是只能看到空白頁。此設(shè)置將會在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.可以立即為將此區(qū)域的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 實現(xiàn)要求地址 addr 是頁對齊的,并允許長度為零。 如果指定地址范圍的某些部分未映射,則 madvise() 的 Linux 版本將忽略它們并將調(diào)用應用于其余部分(但應從系統(tǒng)調(diào)用中返回 ENOMEM)。