內(nèi)存映射和普通文件訪問的區(qū)別_第1頁
內(nèi)存映射和普通文件訪問的區(qū)別_第2頁
內(nèi)存映射和普通文件訪問的區(qū)別_第3頁
內(nèi)存映射和普通文件訪問的區(qū)別_第4頁
內(nèi)存映射和普通文件訪問的區(qū)別_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、在講述文件映射的概念時, 不可避免的要牽涉到虛存(SVR 4的VM). 實(shí)際上, 文件映射是虛存的中心概念, 文件映射一方面給用戶提供了一組措施, 好似用戶將文件映射到自己地址空間的某個部分, 使用簡單的內(nèi)存訪問指令讀寫文件;另一方面, 它也可以用于內(nèi)核的基本組織模式, 在這種模式種, 內(nèi)核將整個地址空間視為諸如文件之類的一組不同對象的映射. 中的傳統(tǒng)文件訪問方式是, 首先用open系統(tǒng)調(diào)用打開文件, 然后使用read, write以及l(fā)seek等調(diào)用進(jìn)行順序或者隨即的I/O. 這種方式是非常低效的, 每一次I/O操作都需要一次系統(tǒng)調(diào)用. 另外, 如果若干個進(jìn)程訪問同一個文件, 每個進(jìn)程都要在

2、自己的地址空間維護(hù)一個副本, 浪費(fèi)了內(nèi)存空間. 而如果能夠通過一定的機(jī)制將頁面映射到進(jìn)程的地址空間中, 也就是說首先通過簡單的產(chǎn)生某些內(nèi)存管理數(shù)據(jù)結(jié)構(gòu)完成映射的創(chuàng)建. 當(dāng)進(jìn)程訪問頁面時產(chǎn)生一個缺頁中斷, 內(nèi)核將頁面讀入內(nèi)存并且更新頁表指向該頁面. 而且這種方式非常方便于同一副本的共享.VM是面向?qū)ο蟮姆椒ㄔO(shè)計的, 這里的對象是指內(nèi)存對象: 內(nèi)存對象是一個軟件抽象的概念, 它描述內(nèi)存區(qū)與后備存儲之間的映射. 系統(tǒng)可以使用多種類型的后備存儲, 比如交換空間, 本地或者遠(yuǎn)程文件以及幀緩存等等. VM系統(tǒng)對它們統(tǒng)一處理, 采用同一操作集操作, 比如讀取頁面或者回寫頁面等. 每種不同的后備存儲都可以用不

3、同的方法實(shí)現(xiàn)這些操作. 這樣, 系統(tǒng)定義了一套統(tǒng)一的接口, 每種后備存儲給出自己的實(shí)現(xiàn)方法. 這樣, 進(jìn)程的地址空間就被視為一組映射到不同數(shù)據(jù)對象上的的映射組成. 所有的有效地址就是那些映射到數(shù)據(jù)對象上的地址. 這些對象為映射它的頁面提供了持久性的后備存儲. 映射使得用戶可以直接尋址這些對象.值得提出的是, VM體系結(jié)構(gòu)獨(dú)立于Unix系統(tǒng), 所有的Unix系統(tǒng)語義, 如正文, 數(shù)據(jù)及堆棧區(qū)都可以建構(gòu)在基本VM系統(tǒng)之上. 同時, VM體系結(jié)構(gòu)也是獨(dú)立于存儲管理的, 存儲管理是由操作系統(tǒng)實(shí)施的, 如: 究竟采取什么樣的對換和請求調(diào)頁算法, 究竟是采取分段還是分頁機(jī)制進(jìn)行存儲管理, 究竟是如何將虛擬

4、地址轉(zhuǎn)換成為物理地址等等(Linux中是一種叫Three Level Page Table的機(jī)制), 這些都與內(nèi)存對象的概念無關(guān).下面介紹Linux中 VM的實(shí)現(xiàn).一個進(jìn)程應(yīng)該包括一個mm_struct(memory manage struct), 該結(jié)構(gòu)是進(jìn)程虛擬地址空間的抽象描述, 里面包括了進(jìn)程虛擬空間的一些管理信息: start_code, end_code, start_data, end_data, start_brk, end_brk等等信息. 另外, 也有一個指向進(jìn)程虛存區(qū)表(vm_area_struct: virtual memory area)的指針, 該鏈?zhǔn)前凑仗摂M地址的

5、增長順序排列的. 在Linux進(jìn)程的地址空間被分作許多區(qū)(vma), 每個區(qū)(vma)都對應(yīng)虛擬地址空間上一段連續(xù)的區(qū)域, vma是可以被共享和保護(hù)的獨(dú)立實(shí)體, 這里的vma就是前面提到的內(nèi)存對象. 下面是vm_area_struct的結(jié)構(gòu), 其中, 前半部分是公共的, 與類型無關(guān)的一些數(shù)據(jù)成員, 如: 指向mm_struct的指針, 地址范圍等等, 后半部分則是與類型相關(guān)的成員, 其中最重要的是一個指向vm_operation_struct向量表的指針vm_ops, vm_pos向量表是一組虛函數(shù), 定義了與vma類型無關(guān)的接口. 每一個特定的子類, 即每種vma類型都必須在向量表中實(shí)現(xiàn)這些

6、操作. 這里包括了: open, close, unmap, protect, sync, nopage, wppage, swapout這些操作.1. struct vm_area_struct  2. /*公共的, 與vma類型無關(guān)的 */ 3. struct mm_struct * vm_mm; 4. unsigned long vm_start; 5. unsigned long vm_end; 6. struct v

7、m_area_struct *vm_next; 7. pgprot_t vm_page_prot; 8. unsigned long vm_flags; 9. short vm_avl_height; 10. struct vm_area_struct * vm_avl_left; 11. struct vm_area_struct * vm_avl_right; 12. struct vm_area_struct&

8、#160;*vm_next_share; 13. struct vm_area_struct *vm_pprev_share; 14.  15. /* 與類型相關(guān)的 */ 16. struct vm_operations_struct * vm_ops; 17. unsigned long vm_pgoff; 18. struct file * vm_file; 19. unsigned long

9、 vm_raend; 20. void * vm_private_data; 21. ; vm_ops: open, close, no_page, swapin, swapout介紹完VM的基本概念后, 我們可以講述mmap和munmap系統(tǒng)調(diào)用了. mmap調(diào)用實(shí)際上就是一個內(nèi)存對象vma的創(chuàng)建過程, mmap的調(diào)用格式是:void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);其中start是映射地址, length是

10、映射長度, 如果flags的MAP_FIXED不被置位, 則該參數(shù)通常被忽略, 而查找進(jìn)程地址空間中第一個長度符合的空閑區(qū)域;Fd是映射文件的文件句柄, offset是映射文件中的偏移地址;prot是映射保護(hù)權(quán)限, 可以是PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE, flags則是指映射類型, 可以是MAP_FIXED, MAP_PRIVATE, MAP_SHARED, 該參數(shù)必須被指定為MAP_PRIVATE和MAP_SHARED其中之一, MAP_PRIVATE 是創(chuàng)建一個寫時拷貝映射(copy-on-write), 也就是說如果有多個進(jìn)程同時映

11、射到一個文件上, 映射建立時只是共享同樣的存儲頁面, 但是某進(jìn)程企圖修改頁面內(nèi)容, 則復(fù)制一個副本給該進(jìn)程私用, 它的任何修改對其它進(jìn)程都不可見. 而MAP_SHARED則無論修改與否都使用同一副本, 任何進(jìn)程對頁面的修改對其它進(jìn)程都是可見的.mmap系統(tǒng)調(diào)用的實(shí)現(xiàn)過程是:1.先通過文件系統(tǒng)定位要映射的文件;2.權(quán)限檢查, 映射的權(quán)限不會超過文件打開的方式, 也就是說如果文件是以只讀方式打開, 那么則不允許建立一個可寫映射;3.創(chuàng)建一個vma對象, 并對之進(jìn)行初始化;4.調(diào)用映射文件的mmap函數(shù), 其主要工作是給vm_ops向量表賦值;5.把該vma鏈入該進(jìn)程的vma鏈表中, 如果可以和前后

12、的vma合并則合并;6.如果是要求VM_LOCKED(映射區(qū)不被換出)方式映射, 則發(fā)出缺頁請求, 把映射頁面讀入內(nèi)存中.munmap(void * start, size_t length):該調(diào)用可以看作是 mmap的一個逆過程. 它將進(jìn)程中從start開始length長度的一段區(qū)域的映射關(guān)閉, 如果該區(qū)域不是恰好對應(yīng)一個vma, 則有可能會分割幾個或幾個vma.msync(void * start, size_t length, int flags):把映射區(qū)域的修改回寫到后備存儲中. 因?yàn)閙unmap時并不保證頁面回寫, 如果不調(diào)用msync, 那么有可能在munmap后丟失對映射區(qū)的

13、修改. 其中flags可以是MS_SYNC, MS_ASYNC, MS_INVALIDATE, MS_SYNC要求回寫完成后才返回, MS_ASYNC發(fā)出回寫請求后立即返回, MS_INVALIDATE使用回寫的內(nèi)容更新該文件的其它映射. 該系統(tǒng)調(diào)用是通過調(diào)用映射文件的sync函數(shù)來完成工作的.brk(void * end_data_segement):將進(jìn)程的數(shù)據(jù)段擴(kuò)展到 end_data_segement指定的地址, 該系統(tǒng)調(diào)用和mmap的實(shí)現(xiàn)方式十分相似, 同樣是產(chǎn)生一個vma, 然后指定其屬性. 不過在此之前需要做一些合法性檢查, 比如該地址是否大于mm->end_code, e

14、nd_data_segement和mm->brk之間是否還存在其它vma等等. 通過brk產(chǎn)生的vma映射的文件為空, 這和匿名映射產(chǎn)生的vma相似, 關(guān)于匿名映射不做進(jìn)一步介紹. 庫函數(shù)malloc就是通過brk實(shí)現(xiàn)的.Linux提供了內(nèi)存映射函數(shù)mmap, 它把文件內(nèi)容映射到一段內(nèi)存上(準(zhǔn)確說是虛擬內(nèi)存上), 通過對這段內(nèi)存的讀取和修改, 實(shí)現(xiàn)對文件的讀取和修改, 先來看一下mmap的函數(shù)聲明:頭文件:<unistd.h><sys/mman.h>原型: void *mmap(void *addr, size_t length, int prot, int fl

15、ags, int fd, off_t offsize);返回值: 成功則返回映射區(qū)起始地址, 失敗則返回MAP_FAILED(-1).參數(shù):addr: 指定映射的起始地址, 通常設(shè)為NULL, 由系統(tǒng)指定.length: 將文件的多大長度映射到內(nèi)存.prot: 映射區(qū)的保護(hù)方式, 可以是:PROT_EXEC: 映射區(qū)可被執(zhí)行.PROT_READ: 映射區(qū)可被讀取.PROT_WRITE: 映射區(qū)可被寫入.PROT_NONE: 映射區(qū)不能存取.flags: 映射區(qū)的特性, 可以是:MAP_SHARED: 對映射區(qū)域的寫入數(shù)據(jù)會復(fù)制回文件, 且允許其他映射該文件的進(jìn)程共享.MAP_PRIVATE:

16、對映射區(qū)域的寫入操作會產(chǎn)生一個映射的復(fù)制(copy-on-write), 對此區(qū)域所做的修改不會寫回原文件.此外還有其他幾個flags不很常用, 具體查看linux C函數(shù)說明.fd: 由open返回的文件描述符, 代表要映射的文件.offset: 以文件開始處的偏移量, 必須是分頁大小的整數(shù)倍, 通常為0, 表示從文件頭開始映射.下面說一下內(nèi)存映射的步驟:用open系統(tǒng)調(diào)用打開文件, 并返回描述符fd.用mmap建立內(nèi)存映射, 并返回映射首地址指針start.對映射(文件)進(jìn)行各種操作, 顯示(printf), 修改(sprintf).用munmap(void *start, size_t

17、lenght)關(guān)閉內(nèi)存映射.用close系統(tǒng)調(diào)用關(guān)閉文件fd.注意事項:在修改映射的文件時, 只能在原長度上修改, 不能增加文件長度, 因?yàn)閮?nèi)存是已經(jīng)分配好的.Linux-mmap函數(shù)介紹mmap函數(shù)是unix/linux下的系統(tǒng)調(diào)用,來看Unix Netword programming卷二12.2節(jié)對mmap的介紹:The mmap function maps either a file or a Posix shared memory object into the address space of a process.We use this function for three purp

18、oses:1. with a regular file to provide memory-mapped I/O2. with special files to provide anonymous memory mappings3. with shm_open to provide Posix shared memory between unrelated processesmmap系統(tǒng)調(diào)用并不是完全為了用于共享內(nèi)存而設(shè)計的。它本身提供了不同于一般對普通文件的訪問方式,進(jìn)程可以像讀寫內(nèi)存一樣對普通文件的操作。而 Posix或系統(tǒng)V的共享內(nèi)存IPC則純粹用于共享目的,當(dāng)然mmap()實(shí)現(xiàn)共享內(nèi)存

19、也是其主要應(yīng)用之一。mmap系統(tǒng)調(diào)用使得進(jìn)程之間通過映射同一個普通文件實(shí)現(xiàn)共享內(nèi)存。普通文件被映射到進(jìn)程地址空間后,進(jìn)程可以像訪問普通內(nèi)存一樣對文件進(jìn)行訪問,不必再調(diào)用read(),write()等操作。我們的程序中大量運(yùn)用了mmap,用到的正是mmap的這種“像訪問普通內(nèi)存一樣對文件進(jìn)行訪問”的功能。實(shí)踐證明,當(dāng)要對一個文件頻繁的進(jìn)行訪問,并且指針來回移動時,調(diào)用mmap比用常規(guī)的方法快很多。來看看mmap的定義:void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);參數(shù)fd為即將映射到進(jìn)程

20、空間的文件描述字,一般由open()返回,同時,fd可以指定為-1,此時須指定flags參數(shù)中的MAP_ANON,表明進(jìn)行的是匿名映射(不涉及具體的文件名,避免了文件的創(chuàng)建及打開,很顯然只能用于具有親緣關(guān)系的進(jìn)程間通信)。len是映射到調(diào)用進(jìn)程地址空間的字節(jié)數(shù),它從被映射文件開頭offset個字節(jié)開始算起。prot參數(shù)指定共享內(nèi)存的訪問權(quán)限。可取如下幾個值的或:PROT_READ(可讀),PROT_WRITE(可寫),PROT_EXEC(可執(zhí)行),PROT_NONE(不可訪問)。flags由以下幾個常值指定:MAP_SHARED, MAP_PRIVATE, MAP_FIXED。其中,MAP_S

21、HARED,MAP_PRIVATE必選其一,而MAP_FIXED則不推薦使用。如果指定為MAP_SHARED,則對映射的內(nèi)存所做的修改同樣影響到文件。如果是MAP_PRIVATE,則對映射的內(nèi)存所做的修改僅對該進(jìn)程可見,對文件沒有影響。offset參數(shù)一般設(shè)為0,表示從文件頭開始映射。參數(shù)addr指定文件應(yīng)被映射到進(jìn)程空間的起始地址,一般被指定一個空指針,此時選擇起始地址的任務(wù)留給內(nèi)核來完成。函數(shù)的返回值為最后文件映射到進(jìn)程空間的地址,進(jìn)程可直接操作起始地址為該值的有效地址。最后,舉個例子來結(jié)束本節(jié)。4.2節(jié)說過,F(xiàn)ileinformation數(shù)組是以二進(jìn)制的形式寫進(jìn)一個叫inforindex

22、的文件中。那么,當(dāng)要訪問 Fileinformation數(shù)組時,代碼類似這樣:1. struct stat st; 2. char buffer=” inforindex”; 3. Fileinformation *_fileinfoIndexptr = NULL; 4. if(stat(buffer,&st)<0) 5.  6. fprintf(stderr,"error to stat %sn",buffer

23、); 7. exit(-1); 8.  9. / mmap the inforindex to _fileinfoIndexptr 10. int fd=open(buffer, O_RDONLY); 11. if(fd<0) 12.  13. printf("error to open %sn",buffer); 14. exit(-1); 15.  16.  

24、;17. _fileinfoIndexptr=(Fileinformation*)mmap(NULL,st.st_size, PROT_READ,MAP_SHARED,fd,0); 18. if(MAP_FAILED = _fileinfoIndexptr) 19.  20. printf("error to mmap %sn",buffer); 21. close(fd); 22. exit(-1); 23.  24. close(fd);&#

25、160;下面這個例子顯示了把文件映射到內(nèi)存的方法源代碼是:1. /*關(guān)于本文檔* 2. *filename: mmap.c 3. *purpose: 說明調(diào)用mmap把文件映射到內(nèi)存的方法 4. *wrote by: zhoulifa(zhoulifa) 周立發(fā)() 5. Linux愛好者 Linux知識傳播者 SOHO族 開發(fā)者 最擅長C語言 6. *date time:2008-01-27 18:59 上海大雪天,據(jù)說是多

26、年不遇 7. *Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些文檔,當(dāng)然包括你的商業(yè)用途 8. * 但請遵循GPL 9. *Thanks to: 10. *                Ubuntu 本程序在Ubuntu 7.10系統(tǒng)上測試完全正常 11. *      

27、0;         G 我通常通過google搜索發(fā)現(xiàn)許多有用的資料 12. *Hope:希望越來越多的人貢獻(xiàn)自己的力量,為科學(xué)技術(shù)發(fā)展出力 13. * 科技站在巨人的肩膀上進(jìn)步更快!感謝有開源前輩的貢獻(xiàn)! 14. */ 15.  16. #include <sys/mman.h> /* for mmap and munmap */ 17. #

28、include <sys/types.h> /* for open */ 18. #include <sys/stat.h> /* for open */ 19. #include <fcntl.h>     /* for open */ 20. #include <unistd.h>   

29、 /* for lseek and write */ 21. #include <stdio.h> 22.  23. int main(int argc, char *argv) 24.  25. int fd; 26. char *mapped_mem, * p; 27. int flength = 1024; 28. vo

30、id * start_addr = 0; 29. fd = open(argv1, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 30. flength = lseek(fd, 1, SEEK_END); 31. write(fd, "0", 1); /* 在文件最后添加一個空字符,以便下面printf正常工作

31、0;*/ 32. lseek(fd, 0, SEEK_SET); 33. mapped_mem = mmap(start_addr, flength, PROT_READ,        /允許讀 34.  MAP_PRIVATE,       /不允許其它進(jìn)程訪問此內(nèi)存區(qū)域 35.  fd, 0); 36.

32、  37. /* 使用映射區(qū)域. */ 38. printf("%sn", mapped_mem); /* 為了保證這里工作正常,參數(shù)傳遞的文件名最好是一個文本文件 */ 39. close(fd); 40. munmap(mapped_mem, flength); 41. return 0; 42.  編譯運(yùn)行此程序:gcc -Wall mmap.c./a.out text_filename上面的方法因?yàn)橛昧薖ROT_REA

33、D,所以只能讀取文件里的內(nèi)容,不能修改,如果換成PROT_WRITE就可以修改文件的內(nèi)容了。又由于 用了MAAP_PRIVATE所以只能此進(jìn)程使用此內(nèi)存區(qū)域,如果換成MAP_SHARED,則可以被其它進(jìn)程訪問,比如下面的: 1. #include <sys/mman.h> /* for mmap and munmap */ 2. #include <sys/types.h> /* for open */ 3. #inclu

34、de <sys/stat.h> /* for open */ 4. #include <fcntl.h>     /* for open */ 5. #include <unistd.h>    /* for lseek and write */ 6. #include <stdio.h> 7. #include <string.h> /* for memcpy */ 8.  9. int main(int argc, char *argv) 10.  11. int 

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論