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

歡迎訪問 生活随笔!

生活随笔

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

linux

Linux的mmap内存映射机制解析

發布時間:2025/3/21 linux 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux的mmap内存映射机制解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在講述文件映射的概念時,不可避免的要牽涉到虛存(SVR 4VM).實際上,文件映射是虛存的中心概念,文件映射一方面給用戶提供了一組措施,好似用戶將文件映射到自己地址空間的某個部分,使用簡單的內存訪問指令讀寫文件;另一方面,它也可以用于內核的基本組織模式,在這種模式種,內核將整個地址空間視為諸如文件之類的一組不同對象的映射.中的傳統文件訪問方式是,首先用open系統調用打開文件,然后使用read, write以及lseek等調用進行順序或者隨即的I/O.這種方式是非常低效的,每一次I/O操作都需要一次系統調用.另外,如果若干個進程訪問同一個文件,每個進程都要在自己的地址空間維護一個副本,浪費了內存空間.而如果能夠通過一定的機制將頁面映射到進程的地址空間中,也就是說首先通過簡單的產生某些內存管理數據結構完成映射的創建.當進程訪問頁面時產生一個缺頁中斷,內核將頁面讀入內存并且更新頁表指向該頁面.而且這種方式非常方便于同一副本的共享.

? ? ?VM是面向對象的方法設計的,這里的對象是指內存對象:內存對象是一個軟件抽象的概念,它描述內存區與后備存儲之間的映射.系統可以使用多種類型的后備存儲,比如交換空間,本地或者遠程文件以及幀緩存等等. VM系統對它們統一處理,采用同一操作集操作,比如讀取頁面或者回寫頁面等.每種不同的后備存儲都可以用不同的方法實現這些操作.這樣,系統定義了一套統一的接口,每種后備存儲給出自己的實現方法.這樣,進程的地址空間就被視為一組映射到不同數據對象上的的映射組成.所有的有效地址就是那些映射到數據對象上的地址.這些對象為映射它的頁面提供了持久性的后備存儲.映射使得用戶可以直接尋址這些對象.

? ? 值得提出的是, VM體系結構獨立于Unix系統,所有的Unix系統語義,如正文,數據及堆棧區都可以建構在基本VM系統之上.同時, VM體系結構也是獨立于存儲管理的,存儲管理是由操作系統實施的,:究竟采取什么樣的對換和請求調頁算法,究竟是采取分段還是分頁機制進行存儲管理,究竟是如何將虛擬地址轉換成為物理地址等等(Linux中是一種叫Three Level Page Table的機制),這些都與內存對象的概念無關.


一、LinuxVM的實現.

? ? ??一個進程應該包括一個mm_struct(memory manage struct),?該結構是進程虛擬地址空間的抽象描述,里面包括了進程虛擬空間的一些管理信息: start_code, end_code, start_data, end_data, start_brk, end_brk等等信息.另外,也有一個指向進程虛存區表(vm_area_struct: virtual memory area)的指針,該鏈是按照虛擬地址的增長順序排列的.Linux進程的地址空間被分作許多區(vma),每個區(vma)都對應虛擬地址空間上一段連續的區域, vma是可以被共享和保護的獨立實體,這里的vma就是前面提到的內存對象.?

? 下面是vm_area_struct的結構,其中,前半部分是公共的,與類型無關的一些數據成員,:指向mm_struct的指針,地址范圍等等,后半部分則是與類型相關的成員,其中最重要的是一個指向vm_operation_struct向量表的指針vm_ops, vm_pos向量表是一組虛函數,定義了與vma類型無關的接口.每一個特定的子類,即每種vma類型都必須在向量表中實現這些操作.這里包括了: open, close, unmap, protect, sync, nopage, wppage, swapout這些操作.?

[cpp] view plain copy
  • struct?vm_area_struct?{???
  • ????/*公共的,?與vma類型無關的?*/???
  • ????struct?mm_struct?*?vm_mm;???
  • ????unsigned?long?vm_start;???
  • ????unsigned?long?vm_end;???
  • ????struct?vm_area_struct?*vm_next;???
  • ????pgprot_t?vm_page_prot;???
  • ????unsigned?long?vm_flags;???
  • ????short?vm_avl_height;???
  • ????struct?vm_area_struct?*?vm_avl_left;???
  • ????struct?vm_area_struct?*?vm_avl_right;???
  • ????struct?vm_area_struct?*vm_next_share;???
  • ????struct?vm_area_struct?**vm_pprev_share;???
  • ????/*?與類型相關的?*/???
  • ????struct?vm_operations_struct?*?vm_ops;???
  • ????unsigned?long?vm_pgoff;???
  • ????struct?file?*?vm_file;???
  • ????unsigned?long?vm_raend;???
  • ????void?*?vm_private_data;??
  • };???
  • vm_ops: open, close, no_page, swapin, swapout……


    二、驅動中的mmap()函數解析

    ? ? ? ?設備驅動的mmap實現主要是將一個物理設備的可操作區域(設備空間)映射到一個進程的虛擬地址空間。這樣就可以直接采用指針的方式像訪問內存的方式訪問設備。在驅動中的mmap實現主要是完成一件事,就是實際物理設備的操作區域到進程虛擬空間地址的映射過程。同時也需要保證這段映射的虛擬存儲器區域不會被進程當做一般的空間使用,因此需要添加一系列的保護方式。

    [cpp] view plain copy
  • /*主要是建立虛擬地址到物理地址的頁表關系,其他的過程又內核自己完成*/??
  • static?int?mem_mmap(struct?file*?filp,struct?vm_area_struct?*vma)??
  • {??
  • ????/*間接的控制設備*/??
  • ????struct?mem_dev?*dev?=?filp->private_data;??
  • ??????
  • ????/*標記這段虛擬內存映射為IO區域,并阻止系統將該區域包含在進程的存放轉存中*/??
  • ????vma->vm_flags?|=?VM_IO;??
  • ????/*標記這段區域不能被換出*/??
  • ????vma->vm_flags?|=?VM_RESERVED;??
  • ??
  • ????/**/??
  • ????if(remap_pfn_range(vma,/*虛擬內存區域*/??
  • ????????vma->vm_start,?/*虛擬地址的起始地址*/??
  • ????????virt_to_phys(dev->data)>>PAGE_SHIFT,?/*物理存儲區的物理頁號*/??
  • ?????dev->size,????/*映射區域大小*/??????????
  • ????????vma->vm_page_prot?/*虛擬區域保護屬性*/??????
  • ????????))??
  • ????????return?-EAGAIN;??
  • ??
  • ????return?0;??
  • }??
  • 具體的實現分析如下:

    vma->vm_flags |= VM_IO;
    vma->vm_flags |= VM_RESERVED;

    上面的兩個保護機制就說明了被映射的這段區域具有映射IO的相似性,同時保證這段區域不能隨便的換出。就是建立一個物理頁與虛擬頁之間的關聯性。具體原理是虛擬頁和物理頁之間是以頁表的方式關聯起來,虛擬內存通常大于物理內存,在使用過程中虛擬頁通過頁表關聯一切對應的物理頁,當物理頁不夠時,會選擇性的犧牲一些頁,也就是將物理頁與虛擬頁之間切斷,重現關聯其他的虛擬頁,保證物理內存夠用。在設備驅動中應該具體的虛擬頁和物理頁之間的關系應該是長期的,應該保護起來,不能隨便被別的虛擬頁所替換。具體也可參看關于虛擬存儲器的文章。

    接下來就是建立物理頁與虛擬頁之間的關系,即采用函數remap_pfn_range(),具體的參數如下:

    int remap_pfn_range(structvm_area_struct *vma, unsigned long addr,unsigned long pfn, unsigned long size, pgprot_t prot)

    1、struct vm_area_struct是一個虛擬內存區域結構體,表示虛擬存儲器中的一個內存區域。其中的元素vm_start是指虛擬存儲器中的起始地址。
    2、addr也就是虛擬存儲器中的起始地址,通常可以選擇addr = vma->vm_start。
    3、pfn是指物理存儲器的具體頁號,通常通過物理地址得到對應的物理頁號,具體采用virt_to_phys(dev->data)>>PAGE_SHIFT.首先將虛擬內存轉換到物理內存,然后得到頁號。>>PAGE_SHIFT通常為12,這是因為每一頁的大小剛好是4K,這樣右移12相當于除以4096,得到頁號。
    4、size區域大小
    5、區域保護機制。
    返回值,如果成功返回0,否則正數。


    三、系統調用mmap函數解析

    ? ? ? ? 介紹完VM的基本概念后,我們可以講述mmapmunmap系統調用了.mmap調用實際上就是一個內存對象vma的創建過程,

    1、mmap函數

    ? ? ? ?Linux提供了內存映射函數mmap,它把文件內容映射到一段內存上(準確說是虛擬內存上),通過對這段內存的讀取和修改,實現對文件的讀取和修改?。普通文件被映射到進程地址空間后,進程可以向訪問普通內存一樣對文件進行訪問,不必再調用read(),write()等操作

    先來看一下mmap的函數聲明:

    [cpp] view plain copy
  • 頭文件:???
  • <unistd.h>???
  • <sys/mman.h>???
  • ??
  • 原型:?void?*mmap(void?*addr,?size_t?length,?int?prot,?int?flags,?int?fd,?off_t?offsize);???
  • ??
  • /*?
  • 返回值:?成功則返回映射區起始地址,?失敗則返回MAP_FAILED(-1).??
  • ?
  • 參數:??
  • ????addr:?指定映射的起始地址,?通常設為NULL,?由系統指定.??
  • ????length:?將文件的多大長度映射到內存.??
  • ????prot:?映射區的保護方式,?可以是:??
  • ????????PROT_EXEC:?映射區可被執行.??
  • ????????PROT_READ:?映射區可被讀取.??
  • ????????PROT_WRITE:?映射區可被寫入.??
  • ????????PROT_NONE:?映射區不能存取.??
  • ????flags:?映射區的特性,?可以是:??
  • ????????MAP_SHARED:?對映射區域的寫入數據會復制回文件,?且允許其他映射該文件的進程共享.??
  • ????????MAP_PRIVATE:?對映射區域的寫入操作會產生一個映射的復制(copy-on-write),?對此區域所做的修改不會寫回原文件.??
  • ????????此外還有其他幾個flags不很常用,?具體查看linux?C函數說明.??
  • ????fd:?由open返回的文件描述符,?代表要映射的文件.??
  • ????offset:?以文件開始處的偏移量,?必須是分頁大小的整數倍,?通常為0,?表示從文件頭開始映射.?
  • */??
  • mmap的作用是映射文件描述符fd指定文件的 [off,off + len]區域至調用進程的[addr, addr + len]的內存區域, 如下圖所示:


    mmap系統調用的實現過程是

    1.先通過文件系統定位要映射的文件;

    2.權限檢查,映射的權限不會超過文件打開的方式,也就是說如果文件是以只讀方式打開,那么則不允許建立一個可寫映射;?

    3.創建一個vma對象,并對之進行初始化;?

    4.調用映射文件的mmap函數,其主要工作是給vm_ops向量表賦值;

    5.把該vma鏈入該進程的vma鏈表中,如果可以和前后的vma合并則合并;

    6.如果是要求VM_LOCKED(映射區不被換出)方式映射,則發出缺頁請求,把映射頁面讀入內存中.


    2、munmap函數

    ? ? ? munmap(void * start, size_t length):

    ? ? ? 該調用可以看作是mmap的一個逆過程.它將進程中從start開始length長度的一段區域的映射關閉,如果該區域不是恰好對應一個vma,則有可能會分割幾個或幾個vma.

    ? ? ? msync(void * start, size_t length, int flags):

    ? ? ?把映射區域的修改回寫到后備存儲中.因為munmap時并不保證頁面回寫,如果不調用msync,那么有可能在munmap后丟失對映射區的修改.其中flags可以是MS_SYNC, MS_ASYNC, MS_INVALIDATE, MS_SYNC要求回寫完成后才返回, MS_ASYNC發出回寫請求后立即返回, MS_INVALIDATE使用回寫的內容更新該文件的其它映射.該系統調用是通過調用映射文件的sync函數來完成工作的.

    ? ? ?brk(void * end_data_segement):

    將進程的數據段擴展到end_data_segement指定的地址,該系統調用和mmap的實現方式十分相似,同樣是產生一個vma,然后指定其屬性.不過在此之前需要做一些合法性檢查,比如該地址是否大于mm->end_code, end_data_segementmm->brk之間是否還存在其它vma等等.通過brk產生的vma映射的文件為空,這和匿名映射產生的vma相似,關于匿名映射不做進一步介紹.庫函數malloc就是通過brk實現的.


    四、實例解析

    ? ? ? ?下面這個例子顯示了把文件映射到內存的方法,源代碼是:

    [cpp] view plain copy
  • /************關于本文?檔********************************************?
  • *filename:?mmap.c?
  • *purpose:?說明調用mmap把文件映射到內存的方法?
  • *wrote?by:?zhoulifa(zhoulifa@163.com)?周立發(http://zhoulifa.bokee.com)?
  • Linux愛好者?Linux知識傳播者?SOHO族?開發者?最擅長C語言?
  • *date?time:2008-01-27?18:59?上海大雪天,據說是多年不遇?
  • *Note:?任何人可以任意復制代碼并運用這些文檔,當然包括你的商業用途?
  • *?但請遵循GPL?
  • *Thanks?to:?
  • *????????????????Ubuntu?本程序在Ubuntu?7.10系統上測試完全正常?
  • *????????????????Google.com?我通常通過google搜索發現許多有用的資料?
  • *Hope:希望越來越多的人貢獻自己的力量,為科學技術發展出力?
  • *?科技站在巨人的肩膀上進步更快!感謝有開源前輩的貢獻!?
  • *********************************************************************/??
  • #include?<sys/mman.h>?/*?for?mmap?and?munmap?*/??
  • #include?<sys/types.h>?/*?for?open?*/??
  • #include?<sys/stat.h>?/*?for?open?*/??
  • #include?<fcntl.h>?????/*?for?open?*/??
  • #include?<unistd.h>????/*?for?lseek?and?write?*/??
  • #include?<stdio.h>??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????int?fd;??
  • ????char?*mapped_mem,?*?p;??
  • ????int?flength?=?1024;??
  • ????void?*?start_addr?=?0;??
  • ??
  • ????fd?=?open(argv[1],?O_RDWR?|?O_CREAT,?S_IRUSR?|?S_IWUSR);??
  • ????flength?=?lseek(fd,?1,?SEEK_END);??
  • ????write(fd,?"\0",?1);?/*?在文件最后添加一個空字符,以便下面printf正常工作?*/??
  • ????lseek(fd,?0,?SEEK_SET);??
  • ????mapped_mem?=?mmap(start_addr,?flength,?PROT_READ,????????//允許讀??
  • ????????MAP_PRIVATE,???????//不允許其它進程訪問此內存區域??
  • ????????????fd,?0);??
  • ??????
  • ????/*?使用映射區域.?*/??
  • ????printf("%s\n",?mapped_mem);?/*?為了保證這里工作正常,參數傳遞的文件名最好是一個文本文件?*/??
  • ????close(fd);??
  • ????munmap(mapped_mem,?flength);??
  • ????return?0;??
  • }??
  • 編譯運行此程序:

    gcc -Wall mmap.c
    ./a.out text_filename

    上面的方法因為用了PROT_READ,所以只能讀取文件里的內容,不能修改,如果換成PROT_WRITE就可以修改文件的內容了。又由于 用了MAAP_PRIVATE所以只能此進程使用此內存區域,如果換成MAP_SHARED,則可以被其它進程訪問,比如下面的

    [cpp] view plain copy
  • #include?<sys/mman.h>?/*?for?mmap?and?munmap?*/??
  • #include?<sys/types.h>?/*?for?open?*/??
  • #include?<sys/stat.h>?/*?for?open?*/??
  • #include?<fcntl.h>?????/*?for?open?*/??
  • #include?<unistd.h>????/*?for?lseek?and?write?*/??
  • #include?<stdio.h>??
  • #include?<string.h>?/*?for?memcpy?*/??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????int?fd;??
  • ????char?*mapped_mem,?*?p;??
  • ????int?flength?=?1024;??
  • ????void?*?start_addr?=?0;??
  • ??
  • ????fd?=?open(argv[1],?O_RDWR?|?O_CREAT,?S_IRUSR?|?S_IWUSR);??
  • ????flength?=?lseek(fd,?1,?SEEK_END);??
  • ????write(fd,?"\0",?1);?/*?在文件最后添加一個空字符,以便下面printf正常工作?*/??
  • ????lseek(fd,?0,?SEEK_SET);??
  • ????start_addr?=?0x80000;??
  • ????mapped_mem?=?mmap(start_addr,?flength,?PROT_READ|PROT_WRITE,????????//允許寫入??
  • ????????MAP_SHARED,???????//允許其它進程訪問此內存區域??
  • ????????fd,?0);??
  • ??
  • ????*?使用映射區域.?*/??
  • ????printf("%s\n",?mapped_mem);?/*?為了保證這里工作正常,參數傳遞的文件名最好是一個文本文?*/??
  • ????while((p?=?strstr(mapped_mem,?"Hello")))?{?/*?此處來修改文件?內容?*/??
  • ????????memcpy(p,?"Linux",?5);??
  • ????????p?+=?5;??
  • ????}??
  • ??????
  • ????close(fd);??
  • ????munmap(mapped_mem,?flength);??
  • ????return?0;??
  • }??

  • 五、mmap和共享內存對比

    ? ? ? 共享內存允許兩個或多個進程共享一給定的存儲區,因為數據不需要來回復制,所以是最快的一種進程間通信機制。共享內存可以通過mmap()映射普通文件(特殊情況下還可以采用匿名映射)機制實現,也可以通過系統V共享內存機制實現。應用接口和原理很簡單,內部機制復雜。為了實現更安全通信,往往還與信號燈等同步機制共同使用。

    對比如下:

    ? ? ? mmap機制:就是在磁盤上建立一個文件,每個進程存儲器里面,單獨開辟一個空間來進行映射。如果多進程的話,那么不會對實際的物理存儲器(主存)消耗太大。

    ? ? ? shm機制:每個進程的共享內存都直接映射到實際物理存儲器里面。

    1、mmap保存到實際硬盤,實際存儲并沒有反映到主存上。優點:儲存量可以很大(多于主存);缺點:進程間讀取和寫入速度要比主存的要慢。

    2、shm保存到物理存儲器(主存),實際的儲存量直接反映到主存上。優點,進程間訪問速度(讀寫)比磁盤要快;缺點,儲存量不能非常大(多于主存)

    使用上看: 如果分配的存儲量不大,那么使用shm;如果存儲量大,那么使用mmap

    總結

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

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

    主站蜘蛛池模板: 国产精品久久伊人 | 美女污污网站 | 双腿张开被9个男人调教 | 日韩美女视频一区二区 | 国产欧美一级片 | 天天操导航| 免费看国产视频 | 精品国产乱码久久久久久蜜柚 | 国产男女自拍 | 大肉大捧一进一出好爽 | 视频在线观看免费大片 | 国产小视频在线看 | 黄色777 | 亚洲一级在线 | 66亚洲一卡2卡新区成片发布 | 玖玖五月 | 阿v视频免费在线观看 | 波多野结衣中文一区 | 国产精品二区一区二区aⅴ 一卡二卡三卡在线观看 | 欧美视频在线免费看 | 国产又黄又粗又猛又爽视频 | 福利视频二区 | 日韩欧美黄色网址 | 欧美高清另类 | 爱情岛论坛永久入口 | 成人在线视频免费看 | 久久国产精品一区 | 成人交配视频 | 91麻豆蜜桃| 三级黄色免费片 | 国产视频第三页 | 善良的少妇伦理bd中字 | 香蕉视频91 | 成a人片亚洲日本久久 | av中出在线 | 亚洲国产精品久久AV | 国产成人无码专区 | 超碰干 | 国产只有精品 | 欧美36p| 国产九九在线 | 极品国产一区 | 91视频爱爱| 成人视品 | 一区三区在线观看 | 国产欧美一区二区三区在线看蜜臀 | www.国产精品| 国产色图视频 | 亚洲AV无码国产成人久久 | 五月香蕉网 | 亚洲无限观看 | 五号特工组之偷天换月 | 国产三级一区 | 欧美自拍偷拍一区二区 | 中文字幕精品久久久久人妻红杏1 | 免费看一级黄色大全 | 自拍偷拍另类 | 日韩高清一区 | 一区二区三区四区日韩 | 黄色片免费网站 | 一级黄色大片网站 | 久久国产色 | 禁欲天堂| 性日韩 | 五月婷婷激情综合网 | 91亚洲精品一区 | 337p日本欧洲亚洲大胆精筑 | 欧美一级在线视频 | 99热这里都是精品 | 日韩欧美一区在线观看 | 精品少妇一区二区三区免费观看 | 丁香婷婷综合网 | 免费一级a毛片夜夜看 | 色一涩 | 日本一级淫片色费放 | 日日爽视频 | 免费看亚洲 | 中文字幕亚洲综合 | 粉嫩aⅴ一区二区三区 | 老色驴综合网 | 青青草手机视频在线观看 | 秋霞在线观看视频 | 一卡二卡三卡在线视频 | 亚洲av网址在线 | 欧美11p| 欧美成人高清在线 | 成人在线国产视频 | 3p视频在线观看 | 综合久久久久久久 | 在线免费观看日韩av | 午夜免费福利视频 | 久久av高潮av无av萌白 | 国产综合区 | 黄色视屏网站 | 国产欧美精品一区二区色综合 | 毛片免费播放 | 好吊视频一区二区三区四区 | 91资源站 | 亚洲经典久久 |