是時(shí)候了解下 mmap 了

1、mmap基礎(chǔ)概念

mmap 是一種內(nèi)存映射文件的方法,即將一個(gè)文件或者其他對象映射到進(jìn)程的地址空間,實(shí)現(xiàn)文件磁盤地址和進(jìn)程虛擬地址空間中一段虛擬地址的一一映射關(guān)系。

實(shí)現(xiàn)這樣的映射關(guān)系后,進(jìn)程就可以采用指針的方式讀寫操作這一段內(nèi)存,而系統(tǒng)會自動(dòng)回寫臟頁面到對應(yīng)的文件磁盤上,即完成了對文件的操作而不必調(diào)用read,write等系統(tǒng)調(diào)用函數(shù)。相反,內(nèi)核空間的這段區(qū)域的修改也直接反應(yīng)用戶空間,從而可以實(shí)現(xiàn)不同進(jìn)程的文件共享。如下圖所示:

img

由上圖可以看出,進(jìn)程的虛擬地址空間,由多個(gè)虛擬內(nèi)存區(qū)域構(gòu)成。虛擬內(nèi)存區(qū)域是進(jìn)程的虛擬地址空間中的一個(gè)同質(zhì)區(qū)間,即具有同樣特性的連續(xù)地址范圍。上圖中所示的text數(shù)據(jù)段、初始數(shù)據(jù)段、Bss數(shù)據(jù)段、堆、棧、內(nèi)存映射,都是一個(gè)獨(dú)立的虛擬內(nèi)存區(qū)域。而為內(nèi)存映射服務(wù)的地址空間處在堆棧之間的空余部分。

linux 內(nèi)核使用的vm_area_struct 結(jié)構(gòu)來表示一個(gè)獨(dú)立的虛擬內(nèi)存區(qū)域,由于每個(gè)不同質(zhì)的虛擬內(nèi)存區(qū)域功能和內(nèi)部機(jī)制不同;因此同一個(gè)進(jìn)程使用多個(gè)vm_area_struct 結(jié)構(gòu)來分別表示不同類型的虛擬內(nèi)存區(qū)域。各個(gè)vm_area_struct 結(jié)構(gòu)使用鏈表或者樹形結(jié)構(gòu)鏈接,方便進(jìn)程快速訪問。如下圖所示:

img

vm_area_struct 結(jié)構(gòu)中包含區(qū)域起始和終止地址以及其他相關(guān)信息,同時(shí)也包含一個(gè)vm_ops 指針,其內(nèi)部可引出所有針對這個(gè)區(qū)域可以使用的系統(tǒng)調(diào)用函數(shù)。這樣,進(jìn)程對某一虛擬內(nèi)存區(qū)域的任何操作都需要的信息,都可以從vm_area_struct 中獲得。mmap函數(shù)就是要?jiǎng)?chuàng)建一個(gè)新的vm_area_struct結(jié)構(gòu) ,并將其與文件的物理磁盤地址相連。具體步驟如下:

2、mmap 內(nèi)存映射原理

mmap 內(nèi)存映射實(shí)現(xiàn)過程,總的來說可以分為三個(gè)階段:

(一)進(jìn)程啟動(dòng)映射過程,并在虛擬地址空間中為映射創(chuàng)建虛擬映射區(qū)域

1、進(jìn)程在用戶空間調(diào)用函數(shù)mmap ,原型:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

2、在當(dāng)前進(jìn)程虛擬地址空間中,尋找一段空閑的滿足要求的連續(xù)的虛擬地址

3、為此虛擬區(qū)分配一個(gè)vm_area_struct 結(jié)構(gòu),接著對這個(gè)結(jié)構(gòu)各個(gè)區(qū)域進(jìn)行初始化

4、將新建的虛擬區(qū)結(jié)構(gòu)(vm_area_struct)插入進(jìn)程的虛擬地址區(qū)域鏈表或樹中

(二)調(diào)用內(nèi)核空間的系統(tǒng)調(diào)用函數(shù)mmap (不同于用戶空間函數(shù)),實(shí)現(xiàn)文件物理地址和進(jìn)程虛擬地址的一一映射關(guān)系

5、為映射分配新的虛擬地址區(qū)域后,通過待映射的文件指針,在文件描述符表中找到對應(yīng)的文件描述符,通過文件描述符,鏈接到內(nèi)核“已打開文集”中該文件結(jié)構(gòu)體,每個(gè)文件結(jié)構(gòu)體維護(hù)者和這個(gè)已經(jīng)打開文件相關(guān)各項(xiàng)信息。

6、通過該文件的文件結(jié)構(gòu)體,鏈接到file_operations模塊,調(diào)用內(nèi)核函數(shù)mmap,其原型為:int mmap(struct file *filp, struct vm_area_struct *vma),不同于用戶空間庫函數(shù)。

7、內(nèi)核mmap函數(shù)通過虛擬文件系統(tǒng)inode模塊定位到文件磁盤物理地址。

8、通過remap_pfn_range函數(shù)建立頁表,即實(shí)現(xiàn)了文件地址和虛擬地址區(qū)域的映射關(guān)系。此時(shí),這片虛擬地址并沒有任何數(shù)據(jù)關(guān)聯(lián)到主存中。

(三)進(jìn)程發(fā)起對這片映射空間的訪問,引發(fā)缺頁異常,實(shí)現(xiàn)文件內(nèi)容到物理內(nèi)存(主存)的拷貝。

前兩個(gè)階段僅在于創(chuàng)建虛擬區(qū)間并完成地址映射,但是并沒有將任何文件數(shù)據(jù)拷貝至主存。真正的文件讀取是當(dāng)進(jìn)程發(fā)起讀或者寫操作時(shí)。

9、進(jìn)程的讀寫操作訪問虛擬地址空間這一段映射地址后,通過查詢頁表,先這一段地址并不在物理頁面。因?yàn)槟壳爸唤⒘擞成洌嬲挠脖P數(shù)據(jù)還沒有拷貝到內(nèi)存中,因此引發(fā)缺頁異常。

10、缺頁異常進(jìn)行一系列判斷,確定無法操作后,內(nèi)核發(fā)起請求掉頁過程。

11、調(diào)頁過程先在交換緩存空間中尋找需要訪問的內(nèi)存頁,,如果沒有則調(diào)用nopage函數(shù)把所缺的頁從磁盤裝入到主存中。

12、之后進(jìn)程即可對這片主存進(jìn)行讀或者寫的操作了,如果寫操作改變了內(nèi)容,一定時(shí)間后系統(tǒng)自動(dòng)回寫臟頁面到對應(yīng)的磁盤地址,也即完成了寫入到文件的過程。

注:修改過的臟頁面并不會立即更新回文件,而是有一段時(shí)間延遲,可以調(diào)用msync() 來強(qiáng)制同步,這樣所寫的內(nèi)容就能立即保存到文件里了。

3、mmap和常規(guī)文件操作的區(qū)別

首先我們來回顧一下常規(guī)文件操作,函數(shù)的調(diào)用過程:

1、進(jìn)程發(fā)起讀文件請求

2、內(nèi)核通過查找進(jìn)程文件符表。

3、inode在address_space上查找要請求的文件頁是否已經(jīng)緩存在頁緩存中。如果存在,則直接返回這片文件頁的內(nèi)容。

總的來說,常規(guī)文件操作為了提高讀寫效率和保護(hù)磁盤,使用了頁緩存機(jī)制,這樣造成了讀文件時(shí)需要先將文件頁從磁盤拷貝到緩存中,由于頁緩存處在內(nèi)核空間,不能被用戶進(jìn)程直接尋址,所以還需要將頁緩存中數(shù)據(jù)頁再次拷貝到內(nèi)存對用的用戶空間中。這樣通過兩次拷貝過程,才能完成進(jìn)程對文件內(nèi)容的獲取。寫操作也一樣,待寫入的Buffer在內(nèi)核空間不能直接訪問,必須先拷貝到內(nèi)核空間對應(yīng)的主存,再回寫磁盤中,也是需要兩次數(shù)據(jù)拷貝。而使用mmap 操作文件中,創(chuàng)建新的虛擬內(nèi)存區(qū)域、建立文件磁盤地址和內(nèi)存區(qū)域映射這兩步,沒有任何文件拷貝操作。而之后訪問數(shù)據(jù)時(shí),發(fā)現(xiàn)內(nèi)存中并無數(shù)據(jù)而發(fā)起的缺失頁異常過程,可以通過建立好的映射關(guān)系,只使用一次數(shù)據(jù)拷貝,就從磁盤中將數(shù)據(jù)傳入內(nèi)存的用戶空間中,供過程使用。

總而言之,常規(guī)的文件操作需要從磁盤到頁緩存再到用戶主存的兩次數(shù)據(jù)拷貝,而mmap操作文件,只需要從磁盤到用戶主存的一次數(shù)據(jù)拷貝過程。說白了,mmap的關(guān)鍵點(diǎn)是實(shí)現(xiàn)了用戶空間和內(nèi)核的數(shù)據(jù)直接交互省去了空間不同數(shù)據(jù)不通的繁瑣過程。因此 mmap效率更高。

mmap優(yōu)點(diǎn)總結(jié)

由上文討論可知,mmap 優(yōu)點(diǎn)共有以下幾點(diǎn):

對文件的讀取操作跨過了頁緩存,減少了數(shù)據(jù)的拷貝次數(shù),用內(nèi)存讀寫取代了I/O讀寫,提高了讀取的效率。

實(shí)現(xiàn)了用戶空間和內(nèi)核空間的高校交互方式,兩空間的各自修改操作可以直接反映在映射的區(qū)域內(nèi),從而被對方空間及時(shí)捕捉。

提供進(jìn)程間共享內(nèi)存及互相通信的方式。不管是父子進(jìn)程還是無親緣關(guān)系進(jìn)程,都可以將自身空間用戶映射到同一個(gè)文件或者匿名映射到同一片區(qū)域。從而通過各自映射區(qū)域的改動(dòng),打到進(jìn)程間通信和進(jìn)程間共享的目的。

同時(shí),如果進(jìn)程A和進(jìn)程 B 都映射了區(qū)域C,當(dāng)A第一次讀取C時(shí)候,通過缺頁從磁盤復(fù)制文件頁到內(nèi)存中,但當(dāng)B再讀C的相同頁面時(shí),雖然也會產(chǎn)生缺頁異常,但是不會從磁盤中復(fù)制文件過來,而是直接使用已經(jīng)保存再內(nèi)存中的文件數(shù)據(jù)。

可用于實(shí)現(xiàn)高效的大規(guī)模數(shù)據(jù)傳輸。內(nèi)存空間不足,是制約大數(shù)據(jù)操作的一個(gè)方面,解決方案往往是借助于硬盤空間的協(xié)助,補(bǔ)充內(nèi)存的不足。但是進(jìn)一步造成大量的文件I/O操作,極大影響效率。這個(gè)問題可以通過mmap映射很好的解決。換句話說,但凡需要磁盤空間代替內(nèi)存的時(shí)候,mmap都可以發(fā)揮功效。

mmap使用細(xì)節(jié)

使用mmap需要注意一點(diǎn),mmap映射區(qū)域大小必須是物理頁大小(page_size)的整數(shù)倍,原因是:內(nèi)存的最小粒度是頁,而進(jìn)程虛擬地址空間和內(nèi)存的映射單位也是以頁為單位,為了匹配內(nèi)存操作,mmap從磁盤到虛擬地址空間的映射也必須是頁。

內(nèi)核可以跟蹤被內(nèi)存映射的底層對象,大小。就是說,如果文件的大小一直再擴(kuò)張,只要再映射區(qū)域范圍內(nèi)的數(shù)據(jù),進(jìn)程都可以依法得到,這和映射建立時(shí)文件的大小無關(guān)。

映射建立后,即使文件關(guān)閉,映射依然存在。因?yàn)橛成涞氖谴疟P的地址,不是文件本身,和文件句柄無關(guān),同時(shí)可用于進(jìn)程間通信的有效地址空間,不完全受限于被映射文件的大小,因?yàn)槭前错撚成洹?/p>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,802評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,762評論 2 372

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