1. 程式人生 > >mmap共享內存深入總結

mmap共享內存深入總結

pri fork 耗時 shared 可見性 映射文件 ref 線程 strong

本文寫於2017-03-11,從老賬號遷移到本賬號,原文地址:https://www.cnblogs.com/huangweiyang/p/6534877.html

概述

mmap()系統調用在調用進程的虛擬地址空間中創建一個新的內存映射。munmap()系統調用執行逆操作,即從進程的地址空間刪除一個映射。

映射可以分為兩種:基於文件的映射和匿名映射。文件映射將一個文件區域中的內容映射到進程的虛擬地址空間中。匿名映射(通過使用MAP_ANONYMOUS)標記或映射/dev/zero來創建)並沒有對應的文件區域,該映射中的字節會被初始化為0。

映射既可以是私有的(MAP_PRIVATE),也可以是共享的(MAP_SHARED)。這種差別確定了在共享內存上發生的變更的可見性,對於文件映射來講,這種差別還確定了內核是否會將映射內容上發生的變更傳遞到底層文件上。當一個進程使用MAP_PAIVATE映射一個文件之後,在映射內容上發生的變更對其他進程是不可見的,並且也不會反應到映射文件上。MAP_SHARED文件映射的做法則相反——在映射上發生的變更對其他進程可見並且會反應到映射文件上。

盡管內核會自動地將發生在一個MAP_SHARED映射內容上的變更反應到底層文件上(pdflush線程),但它不保證合適完成這個操作。應用程序可以使用msync()系統調用來顯示地控制一個映射內容何時與映射文件進行同步。

內存映射有多種用途:

  1. 分配進程私有的內存(私有匿名映射)
  2. 對一個進程的文本段和初始化數據段中的內容進行初始化(私有文件映射)
  3. 在通過fork()關聯起來的進程之間共享內存(共享匿名映射)
  4. 執行內存映射I/O,還可以將其與無關簡稱之間的內存共享結合起來(共享文件映射)

在訪問一個映射的內容時可能會遇到兩個信號。如果在訪問映射時違反了映射之上的保護規則(或訪問一個當前未被映射的地址),那麽就會產生一個SIGSEGV信號。對於基於文件的映射來講,如果訪問的映射部分在文件中沒有相關區域與之對應(即映射大於底層文件

,但仍算映射了,而不是未映射),那麽就會產生一個SIGBUS信號。

交換空間過度利用允許系統給進程分配比實際可用的RAM與交換空間之和更多的內存。過度利用之所以可能是因為所有進程都不會全部用完為其分配的內存。使用MAP_NORESERVE標記可以控制每個mmap()調用的過度利用情況,而是用/proc文件則可以控制整個系統的過度利用情況。

mremap()系統調用允許調整一個既有映射的大小。remap_file_pages()系統調用允許創建非線性文件映射。

對於mmap()映射文件和read()文件來說,read()在讀次數少的情況下比mmap()快。因為雖然mmap()不需要read()的那一次內存拷貝,但是硬件的發展,使得內存拷貝消耗時間極大降低了。而且mmap()的開銷在於缺頁中斷,處理任務比較多。並且,mmap之後,再有讀操作不會經過系統調用,所以在LRU比較最近使用的頁時並不占優勢,容易被換出內存。所以,普通讀的情況下(排除反復讀),read()通常比mmap()來得更快。

關於mmap,這裏有一張圖挺有意思的:mmap 文件映射內存詳解。

mmap共享內存深入總結