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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux内存管理之mmap详解

發布時間:2025/3/21 linux 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux内存管理之mmap详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


一.?mmap系統調用

1.?mmap系統調用????

????mmap將一個文件或者其它對象映射進內存。文件被映射到多個頁上,如果文件的大小不是所有頁的大小之和,最后一個頁不被使用的空間將會清零。munmap執行相反的操作,刪除特定地址區域的對象映射。

當使用mmap映射文件到進程后,就可以直接操作這段虛擬地址進行文件的讀寫等操作,不必再調用read,write等系統調用.但需注意,直接對該段內存寫時不會寫入超過當前文件大小的內容.

采用共享內存通信的一個顯而易見的好處是效率高,因為進程可以直接讀寫內存,而不需要任何數據的拷貝。對于像管道和消息隊列等通信方式,則需要在內核和用戶空間進行四次的數據拷貝,而共享內存則只拷貝兩次數據:一次從輸入文件到共享內存區,另一次從共享內存區到輸出文件。實際上,進程之間在共享內存時,并不總是讀寫少量數據后就解除映射,有新的通信時,再重新建立共享內存區域。而是保持共享區域,直到通信完畢為止,這樣,數據內容一直保存在共享內存中,并沒有寫回文件。共享內存中的內容往往是在解除映射時才寫回文件的。因此,采用共享內存的通信方式效率是非常高的。??

????基于文件的映射,在mmap和munmap執行過程的任何時刻,被映射文件的st_atime可能被更新。如果st_atime字段在前述的情況下沒有得到更新,首次對映射區的第一個頁索引時會更新該字段的值。用PROT_WRITE?和?MAP_SHARED標志建立起來的文件映射,其st_ctime?和?st_mtime在對映射區寫入之后,但在msync()通過MS_SYNC?和?MS_ASYNC兩個標志調用之前會被更新。

用法:

#include?

void?*mmap(void?*start,?size_t?length,?int?prot,?int?flags,

int?fd,?off_t?offset);

int?munmap(void?*start,?size_t?length);

返回說明:

成功執行時,mmap()返回被映射區的指針,munmap()返回0。失敗時,mmap()返回MAP_FAILED[其值為(void?*)-1],munmap返回-1。errno被設為以下的某個值

EACCES:訪問出錯

EAGAIN:文件已被鎖定,或者太多的內存已被鎖定

EBADF:fd不是有效的文件描述詞

EINVAL:一個或者多個參數無效

ENFILE:已達到系統對打開文件的限制

ENODEV:指定文件所在的文件系統不支持內存映射

ENOMEM:內存不足,或者進程已超出最大內存映射數量

EPERM:權能不足,操作不允許

ETXTBSY:已寫的方式打開文件,同時指定MAP_DENYWRITE標志

SIGSEGV:試著向只讀區寫入

SIGBUS:試著訪問不屬于進程的內存區

參數:

start:映射區的開始地址。


length:映射區的長度。


prot:期望的內存保護標志,不能與文件的打開模式沖突。是以下的某個值,可以通過or運算合理地組合在一起

PROT_EXEC?//頁內容可以被執行

PROT_READ?//頁內容可以被讀取

PROT_WRITE?//頁可以被寫入

PROT_NONE?//頁不可訪問


flags:指定映射對象的類型,映射選項和映射頁是否可以共享。它的值可以是一個或者多個以下位的組合體

MAP_FIXED?//使用指定的映射起始地址,如果由start和len參數指定的內存區重疊于現存的映射空間,重疊部分將會被丟棄。如果指定的起始地址不可用,操作將會失敗。并且起始地址必須落在頁的邊界上。

MAP_SHARED?//與其它所有映射這個對象的進程共享映射空間。對共享區的寫入,相當于輸出到文件。直到msync()或者munmap()被調用,文件實際上不會被更新。

MAP_PRIVATE?//建立一個寫入時拷貝的私有映射。內存區域的寫入不會影響到原文件。這個標志和以上標志是互斥的,只能使用其中一個。

MAP_DENYWRITE?//這個標志被忽略。

MAP_EXECUTABLE?//同上

MAP_NORESERVE?//不要為這個映射保留交換空間。當交換空間被保留,對映射區修改的可能會得到保證。當交換空間不被保留,同時內存不足,對映射區的修改會引起段違例信號。

MAP_LOCKED?//鎖定映射區的頁面,從而防止頁面被交換出內存。

MAP_GROWSDOWN?//用于堆棧,告訴內核VM系統,映射區可以向下擴展。

MAP_ANONYMOUS?//匿名映射,映射區不與任何文件關聯。

MAP_ANON?//MAP_ANONYMOUS的別稱,不再被使用。

MAP_FILE?//兼容標志,被忽略。

MAP_32BIT?//將映射區放在進程地址空間的低2GB,MAP_FIXED指定時會被忽略。當前這個標志只在x86-64平臺上得到支持。

MAP_POPULATE?//為文件映射通過預讀的方式準備好頁表。隨后對映射區的訪問不會被頁違例阻塞。

MAP_NONBLOCK?//僅和MAP_POPULATE一起使用時才有意義。不執行預讀,只為已存在于內存中的頁面建立頁表入口。


fd:有效的文件描述詞。如果MAP_ANONYMOUS被設定,為了兼容問題,其值應為-1。


offset:被映射對象內容的起點。


2.?系統調用munmap()?

#include?


int?munmap(?void?*?addr,?size_t?len?)?
該調用在進程地址空間中解除一個映射關系,addr是調用mmap()時返回的地址,len是映射區的大小。當映射關系解除后,對原來映射地址的訪問將導致段錯誤發生。?


3.?系統調用msync()?

#include?


int?msync?(?void?*?addr?,?size_t?len,?int?flags)?
一般說來,進程在映射空間的對共享內容的改變并不直接寫回到磁盤文件中,往往在調用munmap()后才執行該操作。可以通過調用msync()實現磁盤上文件內容與共享內存區的內容一致。??


.?系統調用mmap()用于共享內存的兩種方式:?

(1)使用普通文件提供的內存映射:適用于任何進程之間;此時,需要打開或創建一個文件,然后再調用mmap();典型調用代碼如下:?
?
  • fd=open(name, flag, mode);
  • if(fd<0)
  • ???...
  • ptr=mmap(NULL,len , PROT_READ|PROT_WRITE, MAP_SHARED, fd , 0);
  • 通過mmap()實現共享內存的通信方式有許多特點和要注意的地方

    (2)使用特殊文件提供匿名內存映射:適用于具有親緣關系的進程之間;由于父子進程特殊的親緣關系,在父進程中先調用mmap(),然后調用fork()。那么在調用fork()之后,子進程繼承父進程匿名映射后的地址空間,同樣也繼承mmap()返回的地址,這樣,父子進程就可以通過映射區域進行通信了。注意,這里不是一般的繼承關系。一般來說,子進程單獨維護從父進程繼承下來的一些變量。而mmap()返回的地址,卻由父子進程共同維護。?
    對于具有親緣關系的進程實現共享內存最好的方式應該是采用匿名內存映射的方式。此時,不必指定具體的文件,只要設置相應的標志即可.


    三.?mmap進行內存映射的原理

    ?????mmap系統調用的最終目的是將,設備或文件映射到用戶進程的虛擬地址空間,實現用戶進程對文件的直接讀寫,這個任務可以分為以下三步:

    1.在用戶虛擬地址空間中尋找空閑的滿足要求的一段連續的虛擬地址空間,為映射做準備(由內核mmap系統調用完成)

    ? ? ? ?每個進程擁有3G字節的用戶虛存空間。但是,這并不意味著用戶進程在這3G的范圍內可以任意使用,因為虛存空間最終得映射到某個物理存儲空間(內存或磁盤空間),才真正可以使用。

    ? ? ? ?那么,內核怎樣管理每個進程3G的虛存空間呢?概括地說,用戶進程經過編譯、鏈接后形成的映象文件有一個代碼段和數據段(包括data段和bss段),其中代碼段在下,數據段在上。數據段中包括了所有靜態分配的數據空間,即全局變量和所有申明為static的局部變量,這些空間是進程所必需的基本要求,這些空間是在建立一個進程的運行映像時就分配好的。除此之外,堆棧使用的空間也屬于基本要求,所以也是在建立進程時就分配好的,如圖3.1所示:

    ?

    ?

    ?圖3.1??進程虛擬空間的劃分

    ? ? ? 在內核中,這樣每個區域用一個結構struct?vm_area_struct?來表示.它描述的是一段連續的、具有相同訪問屬性的虛存空間,該虛存空間的大小為物理內存頁面的整數倍??梢允褂?cat?/proc//maps來查看一個進程的內存使用情況,pid是進程號.其中顯示的每一行對應進程的一個vm_area_struct結構.

    下面是struct?vm_area_struct結構體的定義:

  • #include <linux/mm_types.h>

  • /* This struct defines a memory VMM memory area.*/

  • struct vm_area_struct {
  • struct mm_struct * vm_mm;/* VM area parameters*/
  • unsigned long vm_start;
  • unsigned long vm_end;

  • /* linked list of VM areas per task, sorted by address*/
  • struct vm_area_struct *vm_next;
  • pgprot_t vm_page_prot;
  • unsigned long vm_flags;

  • /* AVL tree of VM areas per task, sorted by address*/
  • short vm_avl_height;
  • struct vm_area_struct * vm_avl_left;
  • struct vm_area_struct * vm_avl_right;

  • /* For areas with an address space and backing store,
  • vm_area_struct *vm_next_share;
  • struct vm_area_struct **vm_pprev_share;
  • struct vm_operations_struct * vm_ops;
  • unsigned long vm_pgoff; /* offset in PAGE_SIZE units,*not* PAGE_CACHE_SIZE*/
  • struct file * vm_file;
  • unsigned long vm_raend;
  • void * vm_private_data;/* was vm_pte(shared mem)*/
  • };
  • ? ? ? 通常,進程所使用到的虛存空間不連續,且各部分虛存空間的訪問屬性也可能不同。所以一個進程的虛存空間需要多個vm_area_struct結構來描述。在vm_area_struct結構的數目較少的時候,各個vm_area_struct按照升序排序,以單鏈表的形式組織數據(通過vm_next指針指向下一個vm_area_struct結構)。但是當vm_area_struct結構的數據較多的時候,仍然采用鏈表組織的化,勢必會影響到它的搜索速度。針對這個問題,vm_area_struct還添加了vm_avl_hight(樹高)、vm_avl_left(左子節點)、vm_avl_right(右子節點)三個成員來實現AVL樹,以提高vm_area_struct的搜索速度。

      假如該vm_area_struct描述的是一個文件映射的虛存空間,成員vm_file便指向被映射的文件的file結構,vm_pgoff是該虛存空間起始地址在vm_file文件里面的文件偏移,單位為物理頁面。

    圖3.2??進程虛擬地址示意圖?

    因此,mmap系統調用所完成的工作就是準備這樣一段虛存空間,并建立vm_area_struct結構體,將其傳給具體的設備驅動程序.

    2.?建立虛擬地址空間和文件或設備的物理地址之間的映射(設備驅動完成)

    ? 建立文件映射的第二步就是建立虛擬地址和具體的物理地址之間的映射,這是通過修改進程頁表來實現的.mmap方法是file_opeartions結構的成員:

    ??int?(*mmap)(struct?file?*,struct?vm_area_struct?*);


    linux有2個方法建立頁表:

    (1)?使用remap_pfn_range一次建立所有頁表.

    ???int?remap_pfn_range(struct?vm_area_struct?*vma,?unsigned?long?virt_addr,?unsigned?long?pfn,?unsigned?long?size,?pgprot_t?prot);?

    返回值:

    成功返回?0,?失敗返回一個負的錯誤值
    參數說明:

    vma?用戶進程創建一個vma區域


    virt_addr?重新映射應當開始的用戶虛擬地址.?這個函數建立頁表為這個虛擬地址范圍從?virt_addr?到?virt_addr_size.


    pfn?頁幀號,?對應虛擬地址應當被映射的物理地址.?這個頁幀號簡單地是物理地址右移?PAGE_SHIFT?位.?對大部分使用,?VMA?結構的?vm_paoff?成員正好包含你需要的值.?這個函數影響物理地址從?(pfn<


    size?正在被重新映射的區的大小,?以字節.


    prot?給新?VMA?要求的"protection".?驅動可(并且應當)使用在vma->vm_page_prot?中找到的值.

    (2)?使用nopage?VMA方法每次建立一個頁表項.

    ???struct?page?*(*nopage)(struct?vm_area_struct?*vma,?unsigned?long?address,?int?*type);

    返回值:

    成功則返回一個有效映射頁,失敗返回NULL.

    參數說明:

    address?代表從用戶空間傳過來的用戶空間虛擬地址.

    返回一個有效映射頁.


    (3)?使用方面的限制:

    remap_pfn_range不能映射常規內存,只存取保留頁和在物理內存頂之上的物理地址。因為保留頁和在物理內存頂之上的物理地址內存管理系統的各個子模塊管理不到。640?KB?和?1MB?是保留頁可能映射,設備I/O內存也可以映射。如果想把kmalloc()申請的內存映射到用戶空間,則可以通過mem_map_reserve()把相應的內存設置為保留后就可以。

    3.?當實際訪問新映射的頁面時的操作(由缺頁中斷完成)

    (1)??page?cache及swap?cache中頁面的區分:一個被訪問文件的物理頁面都駐留在page?cache或swap?cache中,一個頁面的所有信息由struct?page來描述。struct?page中有一個域為指針mapping?,它指向一個struct?address_space類型結構。page?cache或swap?cache中的所有頁面就是根據address_space結構以及一個偏移量來區分的。 ? (2)?文件與?address_space結構的對應:一個具體的文件在打開后,內核會在內存中為之建立一個struct?inode結構,其中的i_mapping域指向一個address_space結構。這樣,一個文件就對應一個address_space結構,一個?address_space與一個偏移量能夠確定一個page?cache?或swap?cache中的一個頁面。因此,當要尋址某個數據時,很容易根據給定的文件及數據在文件內的偏移量而找到相應的頁面。? (3)?進程調用mmap()時,只是在進程空間內新增了一塊相應大小的緩沖區,并設置了相應的訪問標識,但并沒有建立進程空間到物理頁面的映射。因此,第一次訪問該空間時,會引發一個缺頁異常。?


    (4)?對于共享內存映射情況,缺頁異常處理程序首先在swap?cache中尋找目標頁(符合address_space以及偏移量的物理頁),如果找到,則直接返回地址;如果沒有找到,則判斷該頁是否在交換區?(swap?area),如果在,則執行一個換入操作;如果上述兩種情況都不滿足,處理程序將分配新的物理頁面,并把它插入到page?cache中。進程最終將更新進程頁表。?

    ?注:對于映射普通文件情況(非共享映射),缺頁異常處理程序首先會在page?cache中根據address_space以及數據偏移量尋找相應的頁面。如果沒有找到,則說明文件數據還沒有讀入內存,處理程序會從磁盤讀入相應的頁面,并返回相應地址,同時,進程頁表也會更新.
    (5)?所有進程在映射同一個共享內存區域時,情況都一樣,在建立線性地址與物理地址之間的映射之后,不論進程各自的返回地址如何,實際訪問的必然是同一個共享內存區域對應的物理頁面。 ?

    《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的Linux内存管理之mmap详解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 午夜av网站 | 少妇人妻综合久久中文字幕 | 99久久精品国产色欲 | 国产免费91视频 | 亚洲午夜毛片 | 免费看黄色三级三级 | 成人av专区 | 91大神在线免费观看 | 丁香色婷婷 | 国产精品污www一区二区三区 | 高h捆绑拘束调教小说 | 亚洲成人mv | 91色蝌蚪| 日韩中文字幕有码 | 欧美色图视频在线 | 狠狠操天天操 | 怡红院毛片 | 粉嫩av四季av绯色av | 午夜久久剧场 | www.brazzers.com| 中文字幕av观看 | 亚洲国产aⅴ成人精品无吗 日韩乱论 | 免费黄色美女网站 | 色网站免费| 一级特黄色大片 | 已满十八岁免费观看全集动漫 | 亚洲美女综合 | 冲田杏梨在线 | 一区二区三区精品视频在线观看 | 懂色tv| 999久久精品| 国产伦精品一区二区三区视频免费 | 欧美顶级毛片在线播放 | 制服丝袜av在线播放 | 国产一区二区片 | 国产99久久久国产精品成人免费 | 成人污在线| 欧美在线一二 | 99国产精品一区二区 | 欧美天堂 | 国产成人精品电影 | 国产黄色一级片视频 | 欧美亚洲综合一区 | 国产香蕉9 | 亚洲一区二区三区影视 | 久久夜夜操妹子 | 日韩av网址大全 | 成人小视频在线观看 | 欧美贵妇videos办公室 | 中文字幕人妻丝袜乱一区三区 | 午夜国产在线 | 黄色网炮 | 秋霞av影院 | 91丨porny丨| 亚州av在线播放 | 女人的av | 人人插人人草 | www国产精品 | 免费a级片在线观看 | 日韩成人av影院 | 国产日韩三级 | 国内自拍偷拍 | 黑人精品无码一区二区三区 | a级黄色网址 | jizz黑人 | 日韩精品在线观看一区二区三区 | 99久久久无码国产精品性波多 | 怡红院成永久免费人全部视频 | 国产精品视频免费在线观看 | 亚洲乱色| 国产91一区在线精品 | av在线黄| 不卡视频在线播放 | 中文字幕 自拍偷拍 | 国产女人爽到高潮a毛片 | 日本久色| 淫辱的世界(调教sm)by | www黄色片网站 | 亚洲成人av免费观看 | 亚洲精品国产精品乱码不99按摩 | 97色爱| www亚洲一区| 91国内精品视频 | 视频二区中文字幕 | 污污的视频网站在线观看 | 久久久黄色 | 日韩少妇一区二区 | 亚洲av无码电影在线播放 | 96视频在线| 一级中文片 | 黄色免费看片 | 欧美美女性视频 | 国产欧美熟妇另类久久久 | 亚洲一区二区视频在线 | 日日舔夜夜摸 | 夜夜爱视频 | 日韩中文字幕影院 | 青青视频免费 | www夜片内射视频日韩精品成人 |