mmap内存映射学习笔记
1、進(jìn)行虛擬內(nèi)存結(jié)構(gòu)體
前文《虛擬內(nèi)存管理》我們講到每個進(jìn)程的結(jié)構(gòu)體task_struct中都有一個內(nèi)存描述結(jié)構(gòu)體mm_struct。 mm_struct此結(jié)構(gòu)體描述了進(jìn)程占用虛擬內(nèi)存的情況,包含每個內(nèi)存段的起始地址、結(jié)束地址。
如下圖,除了固定的代碼段、數(shù)據(jù)段、BSS段、堆、棧,還有一個MMAP 段,此段為程序員自己通過mmap()函數(shù)主動生成的一個段,用于將磁盤文檔映射到內(nèi)存中以增加文件訪問效率(也可進(jìn)行進(jìn)程通信)的一種手段。
上述每個段都會生成一個VMA結(jié)構(gòu)體。
2、mmap()的使用方法
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
start :? 指向欲映射的內(nèi)存起始地址,通常設(shè)為 NULL,代表讓系統(tǒng)自動選定地址,映射成功后返回該地址。
? ?length:? 代表將文件中多大的部分映射到內(nèi)存。
? ?prot? :? 映射區(qū)域的保護(hù)方式。可以為以下幾種方式的組合:
? ? ? ? PROT_EXEC 映射區(qū)域可被執(zhí)行
? ? ? ? PROT_READ 映射區(qū)域可被讀取
? ? ? ? PROT_WRITE 映射區(qū)域可被寫入
? ? ? ? PROT_NONE 映射區(qū)域不能存取——需要小于等于文件打開的權(quán)限一致
? ?flags :? 影響映射區(qū)域的各種特性。在調(diào)用mmap()時必須要指定MAP_SHARED 或MAP_PRIVATE。
? ? ? ? MAP_FIXED 如果參數(shù)start所指的地址無法成功建立映射時,則放棄映射,不對地址做修正。通常不鼓勵用此旗標(biāo)。
? ? ? ? MAP_SHARED 對映射區(qū)域的寫入數(shù)據(jù)會復(fù)制回文件內(nèi),而且允許其他映射該文件的進(jìn)程共享。
? ? ? ? MAP_PRIVATE 對映射區(qū)域的寫入操作會產(chǎn)生一個映射文件的復(fù)制,即私人的“寫入時復(fù)制”(copy on write)對此區(qū)域作的任何修改都不會寫回原來的文件內(nèi)容。
? ? ? ? MAP_ANONYMOUS建立匿名映射。此時會忽略參數(shù)fd,不涉及文件,而且映射區(qū)域無法和其他進(jìn)程共享。
? ? ? ? MAP_DENYWRITE只允許對映射區(qū)域的寫入操作,其他對文件直接寫入的操作將會被拒絕。
? ? ? ? MAP_LOCKED 將映射區(qū)域鎖定住,這表示該區(qū)域不會被置換(swap)。
? ?fd? ? :? 要映射到內(nèi)存中的文件描述符。如果使用匿名內(nèi)存映射時,即flags中設(shè)置了MAP_ANONYMOUS,fd設(shè)為-1。有些系統(tǒng)不支持匿名內(nèi)存映射,則可以使用fopen打開/dev/zero文件,然后對該文件進(jìn)行映射,可以同樣達(dá)到匿名內(nèi)存映射的效果。
? ?offset:文件映射的偏移量,通常設(shè)置為0,代表從文件最前方開始對應(yīng),offset必須是PAGE_SIZE的整數(shù)倍。
返回值:若映射成功則返回映射區(qū)的內(nèi)存起始地址,否則返回MAP_FAILED(-1),錯誤原因存于errno 中。
int munmap(void *start, size_t length);——解除mmap的映射
int msync ( void * addr , size_t len, int flags);? ——文件回寫
3、mmap()的作用,將文件或者其他對象映射到內(nèi)存中,使文件操作像通過指針操作內(nèi)存一樣簡單快速
其主要有兩個用途,下面我們就從這兩個方面來講述:
- 內(nèi)存映射
- 進(jìn)程通信
4、內(nèi)存映射,傳統(tǒng)文件訪問緩慢,內(nèi)存映射后操作文件速度加快
傳統(tǒng)文件訪問的缺點(diǎn):
- 效率低:應(yīng)用程序通過read,write,ioctl來訪問硬件設(shè)備,它們都要經(jīng)過兩次的數(shù)據(jù)拷貝,一次是用戶空間和內(nèi)核空間的數(shù)據(jù)拷貝,另外一次是內(nèi)核空間和硬件之間的數(shù)據(jù)拷貝。
- 浪費(fèi)空間: 訪問文件的傳統(tǒng)方法是用open打開它們, 如果有多個進(jìn)程訪問同一個文件, 則每一個進(jìn)程在自己的地址空間都包含有該文件的副本,這不必要地浪費(fèi)了存儲空間.??
下圖說明了兩個進(jìn)程同時讀一個文件的同一頁的情形. 系統(tǒng)要將該頁從磁盤讀到高速緩沖區(qū)中, 每個進(jìn)程再執(zhí)行一個存儲器內(nèi)的復(fù)制操作將數(shù)據(jù)從高速緩沖區(qū)讀到自己的地址空間.?
通過將磁盤文件映射到內(nèi)存中,從而使文件訪問更加高效簡單:
眾多內(nèi)存數(shù)據(jù)庫如MongoDB操作數(shù)據(jù),就是把文件磁盤內(nèi)容映射到內(nèi)存中進(jìn)行處理
5、共享內(nèi)存實(shí)現(xiàn)進(jìn)行通信
進(jìn)程A和進(jìn)程B都將該頁映射到自己的地址空間, 當(dāng)進(jìn)程A第一次訪問該頁中的數(shù)據(jù)時, 它生成一個缺頁中斷. 內(nèi)核此時讀入這一頁到內(nèi)存并更新頁表使之指向它.以后,
當(dāng)進(jìn)程B訪問同一頁面而出現(xiàn)缺頁中斷時, 該頁已經(jīng)在內(nèi)存, 內(nèi)核只需要將進(jìn)程B的頁表登記項(xiàng)指向次頁即可。
6、共享內(nèi)存比管道的優(yōu)勢:共享內(nèi)存比管道和消息隊(duì)列效率高
共享內(nèi)存和消息隊(duì)列,FIFO,管道傳遞消息的區(qū)別:
——消息隊(duì)列,FIFO,管道的消息傳遞方式一般為
1:服務(wù)器得到輸入
2:通過管道,消息隊(duì)列寫入數(shù)據(jù),通常需要從進(jìn)程拷貝到內(nèi)核。
3:客戶從內(nèi)核拷貝到進(jìn)程
4:然后再從進(jìn)程中拷貝到輸出文件
上述過程通常要經(jīng)過4次拷貝,才能完成文件的傳遞。
——共享內(nèi)存只需要
1:從輸入文件到共享內(nèi)存區(qū)
2:從共享內(nèi)存區(qū)輸出到文件
下面是舉例:
7、mmap注意事項(xiàng)
?
?最終被映射文件的內(nèi)容的長度不會超過文件本身的初始大小,即映射不能改變文件的大小。文件被映射部分而不是整個文件決定了進(jìn)程能夠訪問的空間大小
?8、mmap的實(shí)現(xiàn)
- 映射時,在虛擬地址空間中為你創(chuàng)建虛擬映射區(qū)域
進(jìn)程在用戶空間調(diào)用庫函數(shù)mmap
在當(dāng)前進(jìn)程的虛擬地址空間中,尋找一段空閑的滿足要求的連續(xù)的虛擬地址
為此虛擬區(qū)分配一個vm_area_struct結(jié)構(gòu),接著對這個結(jié)構(gòu)的各個域進(jìn)行了初始化
- 調(diào)用內(nèi)核空間的系統(tǒng)調(diào)用函數(shù)mmap,實(shí)現(xiàn)文件物理地址和進(jìn)程虛擬地址的一一映射關(guān)系
完成以上兩部后,這片虛擬地址并沒有任何數(shù)據(jù)關(guān)聯(lián)到主存中。
- 進(jìn)程發(fā)起對這片映射空間的訪問,引發(fā)缺頁異常,實(shí)現(xiàn)文件內(nèi)容到物理內(nèi)存(主存)的拷貝
進(jìn)程的讀或?qū)懖僮髟L問虛擬地址空間這一段映射地址,通過查詢頁表,
發(fā)現(xiàn)這一段地址并不在物理頁面上。因?yàn)槟壳爸唤⒘说刂酚成?#xff0c;真正
的硬盤數(shù)據(jù)還沒有拷貝到內(nèi)存中,因此引發(fā)缺頁異常。處理缺頁異常時
發(fā)現(xiàn)對于的數(shù)據(jù)還沒有寫入內(nèi)存,于是會將文件數(shù)據(jù)換入內(nèi)存。
調(diào)頁過程先在交換緩存空間(swap cache)中尋找需要訪問的內(nèi)存頁,如
果沒有則調(diào)用nopage函數(shù)把所缺的頁從磁盤裝入到主存中
?
轉(zhuǎn)載于:https://www.cnblogs.com/tjyuanxi/p/9394387.html
總結(jié)
以上是生活随笔為你收集整理的mmap内存映射学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js格式化货币金额
- 下一篇: 根据map键值对,生成update与se