mmap和普通文件讀寫的區別和比較 & mmap的注意點


參考 http://www.cnblogs.com/huxiao-tee/p/4660352.html

 

對linux文件系統不了解的朋友,請參閱我之前寫的博文《從內核文件系統看文件讀寫過程》,我們首先簡單的回顧一下常規文件系統操作(調用read/fread等類函數)中,函數的調用過程:

 

1、進程發起讀文件請求。

2、內核通過查找進程文件符表,定位到內核已打開文件集上的文件信息,從而找到此文件的inode。

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

4、如果不存在,則通過inode定位到文件磁盤地址,將數據從磁盤復制到頁緩存。之后再次發起讀頁面過程,進而將頁緩存中的數據發給用戶進程。

 

總結來說,常規文件操作為了提高讀寫效率和保護磁盤使用了頁緩存機制。這樣造成讀文件時需要先將文件頁從磁盤拷貝到頁緩存中,由於頁緩存處在內核空間,不能被用戶進程直接尋址,所以還需要將頁緩存中數據頁再次拷貝到內存對應的用戶空間中。這樣,通過了兩次數據拷貝過程,才能完成進程對文件內容的獲取任務。寫操作也是一樣,待寫入的buffer在內核空間不能直接訪問,必須要先拷貝至內核空間對應的主存再寫回磁盤中(延遲寫回),也是需要兩次數據拷貝。

 

而使用mmap操作文件中,創建新的虛擬內存區域和建立文件磁盤地址和虛擬內存區域映射這兩步,沒有任何文件拷貝操作。而之后訪問數據時發現內存中並無數據而發起的缺頁異常過程,可以通過已經建立好的映射關系,只使用一次數據拷貝,就從磁盤中將數據傳入內存的用戶空間中,供進程使用。

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

 

mmap優點總結

由上文討論可知,mmap優點共有一下幾點:

1、對文件的讀取操作跨過了頁緩存,減少了數據的拷貝次數,用內存讀寫取代I/O讀寫,提高了文件讀取效率。

2、實現了用戶空間和內核空間的高效交互方式。兩空間的各自修改操作可以直接反映在映射的區域內,從而被對方空間及時捕捉。

3、提供進程間共享內存及相互通信的方式。不管是父子進程還是無親緣關系的進程,都可以將自身用戶空間映射到同一個文件或匿名映射到同一片區域。從而通過各自對映射區域的改動,達到進程間通信和進程間共享的目的。

     同時,如果進程A和進程B都映射了區域C,當A第一次讀取C時通過缺頁從磁盤復制文件頁到內存中;但當B再讀C的相同頁面時,雖然也會產生缺頁異常,但是不再需要從磁盤中復制文件過來,而可直接使用已經保存在內存中的文件數據。

4、可用於實現高效的大規模數據傳輸。內存空間不足,是制約大數據操作的一個方面,解決方案往往是借助硬盤空間協助操作,補充內存的不足。但是進一步會造成大量的文件I/O操作,極大影響效率。這個問題可以通過mmap映射很好的解決。換句話說,但凡是需要用磁盤空間代替內存的時候,mmap都可以發揮其功效。

 

mmap使用細節

1、使用mmap需要注意的一個關鍵點是,mmap映射區域大小必須是物理頁大小(page_size)的整倍數(32位系統中通常是4k字節)。原因是,內存的最小粒度是頁,而進程虛擬地址空間和內存的映射也是以頁為單位。為了匹配內存的操作,mmap從磁盤到虛擬地址空間的映射也必須是頁。

2、內核可以跟蹤被內存映射的底層對象(文件)的大小,進程可以合法的訪問在當前文件大小以內又在內存映射區以內的那些字節。也就是說,如果文件的大小一直在擴張,只要在映射區域范圍內的數據,進程都可以合法得到,這和映射建立時文件的大小無關。具體情形參見“情形三”。

3、映射建立之后,即使文件關閉,映射依然存在。因為映射的是磁盤的地址,不是文件本身,和文件句柄無關。同時可用於進程間通信的有效地址空間不完全受限於被映射文件的大小,因為是按頁映射。

 

 

情形一:一個文件的大小是5000字節,mmap函數從一個文件的起始位置開始,映射5000字節到虛擬內存中。

分析:因為單位物理頁面的大小是4096字節,雖然被映射的文件只有5000字節,但是對應到進程虛擬地址區域的大小需要滿足整頁大小,因此mmap函數執行后,實際映射到虛擬內存區域8192個 字節,5000~8191的字節部分用零填充。

 

情形二:一個文件的大小是5000字節,mmap函數從一個文件的起始位置開始,映射15000字節到虛擬內存中,即映射大小超過了原始文件的大小。

分析:由於文件的大小是5000字節,和情形一一樣,其對應的兩個物理頁。那么這兩個物理頁都是合法可以讀寫的,只是超出5000的部分不會體現在原文件中。由於程序要求映射15000字節,而文件只占兩個物理頁,因此8192字節~15000字節都不能讀寫,操作時會返回異常

 

 

情形三:一個文件初始大小為0,使用mmap操作映射了1000*4K的大小,即1000個物理頁大約4M字節空間,mmap返回指針ptr。

分析:如果在映射建立之初,就對文件進行讀寫操作,由於文件大小為0,並沒有合法的物理頁對應,如同情形二一樣,會返回SIGBUS錯誤。

但是如果,每次操作ptr讀寫前,先增加文件的大小,那么ptr在文件大小內部的操作就是合法的。例如,文件擴充4096字節,ptr就能操作ptr ~ [ (char)ptr + 4095]的空間。只要文件擴充的范圍在1000個物理頁(映射范圍)內,ptr都可以對應操作相同的大小。

這樣,方便隨時擴充文件空間,隨時寫入文件,不造成空間浪費。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM