日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

内存映射mmap

發(fā)布時間:2024/4/18 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内存映射mmap 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

先看下白話MMAP:https://www.cnblogs.com/liqiangchn/p/13587437.html

本文鏈接:找不到了

內(nèi)存映射是linux中的一個重要機制,它和虛擬內(nèi)存管理和文件IO都有直接的關(guān)系,本篇將詳細(xì)介紹linux中內(nèi)存映射的原理。

mmap基本概念

? ? ? ? 在介紹內(nèi)存映射之前,首先知道現(xiàn)代計算機系統(tǒng)普遍采用虛擬內(nèi)存的方式管理物理內(nèi)存。在32位機器上每個進(jìn)程都有自己的4G虛擬內(nèi)存空間,其中0-3G屬于用戶空間,是該進(jìn)程獨有的;3-4G之間的是內(nèi)核空間,是計算機中的所有進(jìn)程的內(nèi)核空間和內(nèi)核進(jìn)程所共享的地址空間。必須明確的一點是:用戶空間和內(nèi)核空間屬于虛擬地址空間,是虛擬內(nèi)存中的概念。進(jìn)程地址空間的劃分如圖1所示。

圖 1 進(jìn)程地址空間

? ? ? ? mmap將就是圖1的進(jìn)程空間中用戶空間的內(nèi)存映射區(qū)域和磁盤上的某個文件或者其他對象形成一一對應(yīng)關(guān)系,形成這樣的關(guān)系之后,進(jìn)程就可以采用對虛擬地址(指針)讀寫的方式實現(xiàn)對內(nèi)存映射區(qū)對應(yīng)的物理內(nèi)存的讀寫,而這種讀寫會被系統(tǒng)自動通過后臺線程(flusher)刷到后備存儲空間、或者通過msync調(diào)用刷到對應(yīng)的后備存儲空間,從而不用調(diào)用read(),write()等系統(tǒng)調(diào)用實現(xiàn)對文件的讀寫。如果不同的進(jìn)程映射同一個文件的同樣區(qū)間或者映射同一個匿名對象到各自的虛擬內(nèi)存空間,那么可以實現(xiàn)進(jìn)程之間的通信,這是一種十分高效的IPC方式。

? ? ? ? 從圖1中可以看出進(jìn)程虛擬地址空間中,用戶空間被劃分成很多的段,包含代碼段、數(shù)據(jù)段、未初始化數(shù)據(jù)段、堆、內(nèi)存映射區(qū)還有棧等區(qū)間,每一個區(qū)間都對應(yīng)一個或者多個管理結(jié)構(gòu)體,在內(nèi)核中用vm_area_struct表示。那么進(jìn)程的用戶空間可以表示為vm_area_struct結(jié)構(gòu)體組成的鏈表,如圖2所示。

圖 2 進(jìn)程地址空間中不同區(qū)段在內(nèi)核中的表示

mmap的基本原理

? ? ? ? mmap內(nèi)存映射的實現(xiàn)過程,可以分為三個階段:

一、進(jìn)程在用戶空間調(diào)用mmap啟動映射過程,內(nèi)核在該進(jìn)程的虛擬地址空間中為映射創(chuàng)建虛擬映射區(qū)域結(jié)構(gòu)體---vm_area_struct

? ? ? ? 1.進(jìn)程在用戶空間調(diào)用mmap,函數(shù)原型為

? ? ? ? void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);

? ? ? ? 關(guān)于該系統(tǒng)調(diào)用的中多解釋可以參考《unix環(huán)境高級編程》中14.8節(jié);

? ? ? ? 2.如果start為NULL(一般的使用情況,增強可移植性),則由內(nèi)核在當(dāng)前進(jìn)程的虛擬地址空間中,尋找一段能夠滿足映射長度需求的連續(xù)虛擬地址區(qū)間;

? ? ? ? 3.為尋找到的連續(xù)虛擬地址區(qū)間分配一個vm_area_struct結(jié)構(gòu)體,接著對這個結(jié)構(gòu)體中的各個成員變量進(jìn)行初始化;

? ? ? ? 4.將新建的虛擬區(qū)間結(jié)構(gòu)體插入到當(dāng)前進(jìn)程的vm_area_struct結(jié)構(gòu)體鏈表和相應(yīng)的紅黑樹結(jié)構(gòu)中;

二、調(diào)用內(nèi)核空間的系統(tǒng)函數(shù)mmap(與為用戶空間提供的系統(tǒng)調(diào)用不是一回事),實現(xiàn)文件磁盤地址和進(jìn)程虛擬地址的一一映射關(guān)系

????????1.為映射分配了新的虛擬地址區(qū)域之后,通過待映射的文件描述符在“進(jìn)程文件描述符表”的struct file* fd_array中找到對應(yīng)的指向文件的struct file*,每個進(jìn)程都為該進(jìn)程打開的所有文件保存著一個struct file*數(shù)組,其中的每個元素都是指向“系統(tǒng)文件描述符”的中的struct file的。系統(tǒng)為每個被打開的文件都維護(hù)一個struct file,struct file中存在指向已打開文件的struct path成員,struct path成員中存在指向系統(tǒng)打開的特定文件的struct dentry*,struct dentry存在指向該能夠唯一標(biāo)識該文件的struct inode結(jié)構(gòu)體(這種關(guān)系可以參考博客),簡化圖如圖3。

圖 3 進(jìn)程地址空間、頁緩存和文件系統(tǒng)關(guān)系圖

?

? ? ? ? 2.通過該文件最終找到的struct inode結(jié)構(gòu)體中的struct file_operations* i_fop模塊,調(diào)用內(nèi)核函數(shù)的mmap(也就是驅(qū)動程序,該模塊也是虛擬文件系統(tǒng)和實際文件系統(tǒng)連接的橋梁),其原型為int mmap(struct file* filp, struct vm_area_struct* vma),通過該內(nèi)核函數(shù)就知道這是將虛擬地址區(qū)間和實際的后備文件系統(tǒng)相關(guān)聯(lián)。

? ? ? ? 3.通過1中所述,由struct file能夠找到系統(tǒng)打開的文件所對應(yīng)的inode結(jié)構(gòu)體,并通過inode結(jié)構(gòu)體中設(shè)備號和塊號最終定位到文件在磁盤的物理地址。

? ? ? ? 4.通過remap_pfn_rang函數(shù)建立頁表,實現(xiàn)文件在磁盤中的地址和虛擬地址區(qū)域的映射關(guān)系。此時這片虛擬地址并沒有任何數(shù)據(jù)關(guān)聯(lián)到主存中,只是建立了虛擬地址和磁盤地址之間的映射關(guān)系。

三、進(jìn)程訪問分配的虛擬的地址區(qū)間中的某個地址,引發(fā)缺頁異常,實現(xiàn)文件內(nèi)容到物理內(nèi)存的拷貝

? ? ? ? 1.進(jìn)程的讀或者寫操作訪問虛擬地址區(qū)間中的一個或者一段映射地址,通過查詢頁表,發(fā)現(xiàn)這一段地址并不在主存上存在對應(yīng)的物理頁面。因為目前只是建立了地址映射,真正的硬盤數(shù)據(jù)還沒有拷貝到物理內(nèi)存中,由此引發(fā)缺頁異常。

? ? ? ? 2.缺頁異常通過一系列判斷,確定操作合法后,通過DMA的方式讀取數(shù)據(jù)

? ? ? ? 3.調(diào)頁過程先在交換緩存空間(swap cache)中尋找需要訪問的內(nèi)存頁,如果沒有則調(diào)用nopage函數(shù)把所缺的頁從磁盤裝入到物理內(nèi)存中。這個過程還涉及分配物理頁框、確定物理頁框的地址、將讀取的數(shù)據(jù)寫入物理頁框,最終更新頁表中訪問的虛擬地址對應(yīng)的物理頁框的地址。

? ? ? ? 4.之后進(jìn)程從缺頁異常中恢復(fù)即可讀取該內(nèi)容文件對應(yīng)的實際內(nèi)容或者對文件進(jìn)行寫操作。

? ? ? ??mmap調(diào)用需要說明的一點是物理頁框最終是由內(nèi)核以頁緩存的方式進(jìn)行管理的,參見《linux內(nèi)核設(shè)計與實現(xiàn)》中頁緩存一章。因此,如果是對文件進(jìn)行寫操作,那么臟頁面不會立即更新到文件中,而是暫時寫到頁緩存中,由后臺的flusher線程將對文件的更新寫到磁盤中或者是由用戶調(diào)用msync將對應(yīng)的數(shù)據(jù)刷新到磁盤中。

mmap映射的四種類型

? ? ? ? mmap分為有后備文件的映射和匿名映射,而這兩種映射又都有私有映射和共享映射之分,所以mmap一共存在四種類型的映射。

? ? ? ? 1.有后備文件的共享映射。多個進(jìn)程的vm_area_struct指向同一個物理內(nèi)存區(qū)域,一個進(jìn)程對文件內(nèi)容的修改對其他進(jìn)程可見,對文件內(nèi)容的修改最終會被寫到后備文件中。

? ? ? ? 2.有后備文件的私有映射。多個進(jìn)程的vm_area_struct指向同一個物理內(nèi)存區(qū)域,采用寫時拷貝的方式,當(dāng)一個進(jìn)程對文件內(nèi)容做修改,不會被其他的進(jìn)程所看到,另外對文件內(nèi)容的修改也不會被寫到后備文件。當(dāng)內(nèi)存不夠需要執(zhí)行頁回收操作的時候,私有映射的頁被交換到交換區(qū)或者直接寫到磁盤。一般用在加載共享代碼庫。

? ? ? ? 3.匿名文件的共享映射。內(nèi)核創(chuàng)建一個都是0的物理內(nèi)存區(qū)域,然后多個進(jìn)程的vm_area_struct指向這個共享的物理內(nèi)存區(qū)域,對該區(qū)域內(nèi)容的修改對所有的進(jìn)程都是可見的,匿名文件在頁會頁回收的時候被交換到交換區(qū)。

? ? ? ? 4.匿名文件的私有映射。內(nèi)核創(chuàng)建一個初始都是0的物理內(nèi)存區(qū)域,對該區(qū)域的內(nèi)容的修改只對進(jìn)程創(chuàng)建者可見,匿名文件在頁回收的時候被交換到交換區(qū)。malloc()的底層調(diào)用是用了匿名文件的私有映射來分配大塊的內(nèi)存。

mmap的用途

? ? ? ? 內(nèi)存映射的用途很多,如

? ? ? ? 1.后備文件的共享映射可以用作內(nèi)存映射IO來對大文件進(jìn)行操作,比普通IO減少一次內(nèi)存的拷貝工作。需要注意的是內(nèi)存映射IO涉及到內(nèi)核的很多操作,比如vm_area_struct的創(chuàng)建、頁表的修改等等,比普通的IO操作更加復(fù)雜。小文件的讀寫使用普通IO更合適。

? ? ? ? 2.后備文件的私有映射可以用作共享庫二進(jìn)制文件代碼段,數(shù)據(jù)段的加載。

? ? ? ? 3.匿名文件的共享映射可以用作fork時,讓父子進(jìn)程共享匿名映射分配的內(nèi)存。

? ? ? ? 4.匿名文件的私有映射可以用作進(jìn)程的私有內(nèi)存分配。

?

總結(jié)

以上是生活随笔為你收集整理的内存映射mmap的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。