學習mmap

最近在工作中遇到一個mmap使用相關(guān)的問題薄扁,造成了一定的困惑胁黑,于是花了些時間補了下 mmap的功課涩盾,在這里分享給大家,錯誤和不足之處大家多指教捕捂。

相關(guān)背景知識
  • 說到mmap的使用瑟枫,我們首先要了解一下進程的虛擬進程地址空間的概念。Linux上為了作進程隔離指攒,每個進程都運行在自己的單獨的虛擬進程空間慷妙,同時物理機上內(nèi)存有限,每個進程使用虛擬內(nèi)存地址來隔離又共享物理內(nèi)存允悦。我們平時在代碼里獲取的地址就是虛擬地址;

  • 放一張進程虛擬地址空間草圖膝擂,網(wǎng)上也可以很容易找到更精美的 :)


    5e6793157b730fab2ff932dbfcc0a0183.jpg
  • 我們在程序中申請內(nèi)存的操作,實際上只是在進程地址空間相應部分申請了一段虛擬地址隙弛,當實際對這段虛擬地址進行讀寫操作時架馋,才會分配真正的物理內(nèi)存;

  • 通常x86 Linux采用段頁式的內(nèi)存管理模式,這塊不具體展開全闷,簡單來說就是CPU訪問的邏輯地址叉寂,然后經(jīng)過分段機制轉(zhuǎn)換成線性地址(你可以簡單理解成等價于上面說的虛擬地址),再經(jīng)過分頁機制轉(zhuǎn)換成物理地址室埋,第一次訪問的時候由于實現(xiàn)物理地址還沒有分配办绝,會產(chǎn)生缺頁中斷來分配物理地址,用它來填充對應的頁表項;

  • 通過read系統(tǒng)調(diào)用來讀取磁盤上的文件時姚淆,文件內(nèi)容會先被讀到內(nèi)存的page cache部分孕蝉,然后再從page cache中拷貝到應用層的讀緩存buffer中;對于打開的文件,內(nèi)核都會在內(nèi)存中維護一個inode結(jié)構(gòu)體(對于同一個文件腌逢,即使被open多次降淮,內(nèi)核也僅維護這一個inode),其有一個成員是struct address_space *i_mapping, 它用來維護這個文件被讀取的所有部分在內(nèi)存中的緩存搏讶,其使用xarray(全新封裝了基數(shù)樹的操作)來存儲這個物理頁(struct page), 如下圖:

    048bffd2fdbba353a06eef23bcbde3e8.jpg

mmap簡介
  • 先看原型: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
  • 功能:
    1. 分配一塊新的連續(xù)的進程虛擬地址段(對應內(nèi)核中的結(jié)構(gòu)體就是 vm_area_struct)并返回其起始地址佳鳖,如果給定了第一個參數(shù),就優(yōu)先從這個地址開始分配進程虛擬地址;
    2. 如果提供了fd文件句枘媒惕,則映射文件內(nèi)容到進程虛擬地址;
    3. mmap的參數(shù)較多系吩,其中protflags的可選項也比較多,具體大家可以使用 man命令查看;
mmap的幾種典型應用
  • 不同進程(可以是非父子進程)間共享映射

    1. 這種情況需要借助磁盤文件妒蔚,實際上是共享這個磁盤文件穿挨,將這個磁盤文件映射到各自的進程虛擬地址空間月弛,但是其虛擬地址空間分頁轉(zhuǎn)換后其頁表項對應的物理內(nèi)存是相同的;
    2. 典型用法是需提供一個打開的文件句柄,使用 MAP_SHARED flag
    int fd = open ("[filepath]", O_RDWR))
    void *addr = mmap (NULL, [mmaping length], PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
    
  • 非子進程間通訊

    1. 父進程使用 fork創(chuàng)建子進程科盛,父子進程間可以使用mmap來通讀;
    2. 典型用法是無需提供打開的文件句柄, 使用 MAP_SHARED | MAP_ANONYMOUS flag,
    void *addr = mmap (NULL, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    
  • 進程通過 mmap 來讀寫文件

    1. 從上面 相關(guān)背景知識 一節(jié)可知使用 read系統(tǒng)調(diào)用讀文件時帽衙,數(shù)據(jù)需經(jīng)過 磁盤拷貝到page cache, page cache再拷貝到應用層緩存bufffer, 這兩個數(shù)據(jù)拷貝;
    2. 使用 mmap 時,磁盤數(shù)據(jù)也是先讀到page cache中贞绵,然后會將mmap返回的虛擬地址最終對應的頁項表內(nèi)容設(shè)定為和前面的page chache相同的物理頁厉萝, 這樣一來就免去了第二次的數(shù)據(jù)拷貝;
    3. 用個示意圖來說明一下:


      47e79c5a782b3f6c756725eb9e7f0c51.jpg
  • 用作glibc中malloc申請內(nèi)存

    1. 通常我們都說是通過調(diào)用 malloc來申請堆上內(nèi)存,但實際上其內(nèi)部實現(xiàn)使用了 brkmmap兩種系統(tǒng)調(diào)用榨崩,當申請的內(nèi)存大于128K時谴垫,使用 mmap
    2. 典型用法是無需提供打開的文件句柄, 使用 MAP_PRIVATE | MAP_ANONYMOUS flag
    void *addr = mmap (NULL, buffer_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    
  • mmap的寫時拷貝

    1. 如果我們在調(diào)用mmap時提供一個打開的文件句兩,但使用 MAP_PRIVATE的flags, 那這時對其的寫操作并不能真正修改對應的磁盤文件母蛛,它會作寫時拷貝弹渔,退化成匿名映射
mmap作磁盤文件映射時的特別說明
  • mmap映射的虛擬地址長度(即mmap的第二個參數(shù))需要對齊到物理頁大小,在32位系統(tǒng)上通常是4K, 這一特點會導致一些有趣的事情發(fā)生,我們來看一下:假如一個文件的大小是5000Byte, 剛好比4K大一些溯祸,我們用mmap來從文件開始的位置來映射它,mmap的第二個參數(shù)給5000, 因為需要頁面對齊舞肆,實現(xiàn)映射的虛擬地址長度將是兩個4k,即8192, 8192 - 5000 = 3192的部分用0填充焦辅,也是可以被訪問到;
  • 如果用mmap映射某個文件時,這個文件大小為0, 不會分配任何的物理內(nèi)存椿胯,也不能作任何的讀寫訪問筷登;當向文件中寫入數(shù)據(jù)后,通過mmap返回的虛擬地址可以訪問這部分文件內(nèi)容;
mmap與內(nèi)存換入換出
  • 由前面的介紹我們知道m(xù)map不管是映射磁盤文件哩盲,還是作匿名映射前方,最終都會分配物理內(nèi)存頁,因此這個物理內(nèi)存頁在內(nèi)存緊張時就有備換出的可能廉油,當然mmap提供了MAP_LOCKED惠险,可以鎖定內(nèi)存不被換出,我們不考慮這種情況;
  • 如果使用mmap映射的是磁盤文件抒线,其存在物理頁的內(nèi)容會被清空班巩,pte將記錄這種情況,再次需要訪問時嘶炭,會重新讀取磁盤文件抱慌,緩存在page cache中;
  • 如果使用mmap作匿名映射,沒有相關(guān)聯(lián)的磁盤文件(或者使用MAP_PRIVATE方式映射磁盤文件)眨猎,發(fā)生內(nèi)存換出時抑进,將被交換到swap中,swap實際上也對應著磁盤塊睡陪,最終也是寫在磁盤上;

關(guān)于mmap我們這次就先介紹到這里~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末寺渗,一起剝皮案震驚了整個濱河市匿情,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌户秤,老刑警劉巖码秉,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鸡号,居然都是意外死亡转砖,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門鲸伴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來府蔗,“玉大人,你說我怎么就攤上這事汞窗⌒粘啵” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵仲吏,是天一觀的道長不铆。 經(jīng)常有香客問我,道長裹唆,這世上最難降的妖魔是什么誓斥? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮许帐,結(jié)果婚禮上劳坑,老公的妹妹穿的比我還像新娘。我一直安慰自己成畦,他們只是感情好距芬,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著循帐,像睡著了一般框仔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惧浴,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天存和,我揣著相機與錄音,去河邊找鬼衷旅。 笑死捐腿,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的柿顶。 我是一名探鬼主播茄袖,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嘁锯!你這毒婦竟也來了宪祥?” 一聲冷哼從身側(cè)響起聂薪,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝗羊,沒想到半個月后藏澳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡耀找,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年翔悠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片野芒。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡蓄愁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狞悲,到底是詐尸還是另有隱情撮抓,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布摇锋,位于F島的核電站丹拯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏荸恕。R本人自食惡果不足惜咽笼,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望戚炫。 院中可真熱鬧,春花似錦媳纬、人聲如沸双肤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茅糜。三九已至,卻和暖如春素挽,著一層夾襖步出監(jiān)牢的瞬間蔑赘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工预明, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缩赛,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓撰糠,卻偏偏與公主長得像酥馍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子阅酪,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容

  • Linux進程通信實現(xiàn)機制有很多旨袒,也有各自優(yōu)缺點和適用場景汁针,關(guān)于她們之間的對比,等各種通信機制一一介紹后砚尽,再來一個...
    batbattle閱讀 4,082評論 3 13
  • linux庫函數(shù)mmap()原理 目錄 1.mmap基本概念 2.mmap內(nèi)存映射原理 3.mmap和常規(guī)文件操作...
    小烏龜爸閱讀 927評論 0 3
  • mmap基礎(chǔ)概念 mmap是一種內(nèi)存映射文件的方法施无,即將一個文件或者其它對象映射到進程的地址空間,實現(xiàn)文件磁盤地址...
    神奇的考拉閱讀 2,202評論 3 6
  • UNIX網(wǎng)絡編程第二卷進程間通信對mmap函數(shù)進行了說明必孤。該函數(shù)主要用途有三個:1猾骡、將一個普通文件映射到內(nèi)存中,通...
    宇文黎琴閱讀 3,517評論 0 4
  • mmap基礎(chǔ)概念 mmap是一種內(nèi)存映射文件的方法隧魄,即將一個文件或者其它對象映射到進程的地址空間卓练,實現(xiàn)文件磁盤地址...
    dequal閱讀 1,212評論 0 1