Linux記憶體對映(mmap)簡析

2021-06-19 17:41:20 字數 4772 閱讀 8186

14 #include

15 #include

16 #include

17 #include

18 #include

19 20 

21 #define device_name "mymap"

22 23 

24 static unsigned char array[10]=;

25 static unsigned char *buffer;

26 27 

28 static int my_open(struct inode *inode, struct file *file)

29 32 

33 34 static int my_map(struct file *filp, struct vm_area_struct *vma)

35 54 

55 56 static struct file_operations dev_fops = ;

61 62 static struct miscdevice misc = ;

67 68 

69 static int __init dev_init(void)

70 82 

83 84 static void __exit dev_exit(void)

85 93 

94 95 module_init(dev_init);

96 module_exit(dev_exit);

97 module_license("gpl");

98 module_author("lkn@scut");

應用程式:

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9   www.2cto.com  

10 #define page_size 4096

11 12 

13 int main(int argc , char *argv)

14 26 

27     //記憶體對映

28     p_map = (unsigned char *)mmap(0, page_size, prot_read | prot_write, map_shared,fd, 0);

29     if(p_map == map_failed)

30      www.2cto.com  

34 35     //列印對映後的記憶體中的前10個位元組內容

36     for(i=0;i<10;i++)

37         printf("%d\n",p_map[i]);

38     

39 40 here:

41     munmap(p_map, page_size);

42     return 0;

43 }

實際上,記憶體對映機制並不是完全為了共享記憶體的目的而設計的,它本身提供了不同於一般普通檔案的訪問方式,程序可以像訪問記憶體一樣對普通檔案程序操作.而posix或system v共享記憶體ipc則純粹是用於共享記憶體的目的.當然記憶體對映實現共享記憶體,也是記憶體對映的應用之一;

記憶體對映機制的用途:a、以訪問記憶體的方式讀寫檔案; b、實現共享記憶體;

、mmap()系統呼叫:

mmap()系統呼叫使得程序之間通過對映同乙個普通檔案而實現共享記憶體的目的.普通檔案被對映到程序的位址空間之後,程序就可以像訪問普通記憶體一樣對檔案進行訪問,不必再呼叫read()、write()等系統呼叫操作.

mmap()系統呼叫介紹:

void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset);

該函式在程序的位址空間與檔案物件或共享記憶體物件之間建立一種對映關係;

addr  :該引數指定檔案應該被對映到程序位址空間的起始位址,一般被指定為乙個空指標,此時,程式把選擇起始位址的任務留給核心來完成了.這個位址是程序位址空間中需要對映到檔案中的記憶體區域的首位址;也就是說,在程序位址空間中用於檔案對映的記憶體區域的首位址;

len   :檔案被對映到呼叫程序的位址空間中的位元組數,它從被對映檔案開頭offset個位元組處開始算起,取len個位元組,把檔案中的這len個位元組的檔案空間對映到程序的位址空間中;

port  :指定檔案被對映到記憶體中之後的訪問許可權.可取的值有:port_read(可讀)、port_write(可寫)、port_exec(可執行)、port_none(不可訪問);

flags :對映標記;取值如下:map_shared、map_private、map_fixed,其中,map_shared和map_private必選其一,而map_fixed則不推薦使用;

fd    :即將被對映到程序位址空間中的檔案的描述符.一般由系統呼叫open()返回;同時,fd可以指定為-1,此時,必須指定flags引數中的map_anon,表明程序的是匿名對映(不涉及具體的檔名,避免了檔案的建立及開啟,很顯然,只能用於具有親屬關係的程序之間的通訊).

offset:從檔案開頭計算offset個位元組處開始對映;也就是,檔案中需要被對映的檔案內容的起始位址,這個起始位址的計算是以檔案開頭為參照的;這個引數一般取值為0,表示從檔案開頭處開始對映;

返回值:檔案最終對映到程序位址空間中的起始位址;程序可直接以該位址為有效的起始位址進行操作;也就是檔案中開始對映的起始字節點到程序中對應對映記憶體區的起始位址點處的乙個對映;換句話就是說,在程序位址空間中用於檔案對映的記憶體區域的首位址;

a、使用普通檔案提供的記憶體對映/共享記憶體:適用於任何程序之間;此時,需要使用系統呼叫open()事先開啟或建立乙個檔案,然後再呼叫mmap():

fd = open(filename, flag, mode);

......

ptr = mmap(null, len, port_read|port_write, map_shared, fd, 0);

使用特殊檔案提供匿名記憶體對映:適用於具有親屬關係的程序之間;由於父子程序之間的這種特殊的父子關係,在父程序中先呼叫mmap(),然後呼叫fork(),那麼,在呼叫fork()之後,子程序繼承了父程序的所有資源,當然也包括匿名對映後的位址空間和mmap()返回的位址,這樣,父子程序就可以通過對映區域進行通訊了;

注意:這裡不是一般的繼承關係.一般來說,子程序單獨維護從父程序繼承下來的一些變數,而mmap()返回的位址卻是由父子程序共同維護的;對於具有親屬關係的程序之間實現共享記憶體的最好方式應該是採用匿名對映的方式.此時,不必指定具體的條件,只要設定相應的標誌即可.

當程序間通訊結束時,需要解除檔案頁面空間到程序位址空間之間的對映關係;也就說,程序通訊結束時,需要把掛載到程序位址空間上的檔案解除安裝下來;這個任務由系統呼叫munmap();

int munmap(void* addr, size_t len);

該系統呼叫用於在程序位址空間中結束對映關係;

addr:是呼叫mmap()返回的程序位址空間中用於檔案對映的記憶體區域的首位址;

len :程序位址空間中對映區域的大小,單位:位元組;

當對映關係解除之後,對原來對映位址的訪問將導致段錯誤發生;

返回值: -1:失敗; 0:成功;

一般來說,程序在對映空間中對共享內容的修改並不會直接寫回到磁碟檔案中,往往在呼叫munmap()之後才會同步輸出到磁碟檔案中.那麼,在程式執行過程中,在呼叫munmap()之前,可以通過呼叫msync()來實現磁碟上檔案內容與共享記憶體區中的內容與一致;或者是把對共享記憶體區的修改同步輸出到磁碟檔案中;

注意:

1、最終被對映檔案內容的長度不會超過檔案本身的初始大小,即:記憶體對映操作不能改變檔案的大小;

2、可以用於程序間通訊的得有效位址空間大小大體上受限於被對映檔案的大小,但是並不完全受限於檔案大小.

在linux中,記憶體的保護機制是以記憶體頁為單位的,即使被對映的檔案只有乙個位元組的大小,核心也會為這個檔案的對映分配乙個頁面大小的記憶體空間.當被對映檔案的大小小於乙個頁面大小時,程序可以對mmap()返回位址開始的乙個頁面大小進行訪問,而不會出錯;但是,如果對乙個頁面之外的位址空間進行訪問,則導致錯誤發生.因此,可用於程序間通訊的有效位址空間的大小不會超過被對映檔案大小與乙個頁面大小的和;

3、檔案一旦被對映之後,呼叫mmap()的程序對返回位址空間的訪問就是對某一記憶體區域進行訪問,暫時脫離了磁碟上檔案的影響.所有對mmap()返回位址空間的操作只在記憶體範圍內有意義,只有在呼叫了munmap()或msync()之後,才會把對映記憶體中的相應內容寫回到磁碟檔案中,所寫內容的大小仍然不會超過被對映檔案的大小;

linux採用的是頁式管理機制.對於用mmap()對映普通檔案來說,程序會在自己的位址空間中新增加一塊空間,空間的大小由mmap()的len引數指定,注意:程序並不一定能夠對新增加的全部空間都進行有效的訪問.程序能夠訪問的有效位址空間的大小取決於檔案中被對映部分的大小.簡單地說,能夠容納檔案中被對映部分大小的最少頁面個數決定了程序從mmap()返回的位址開始,能夠訪問的有效位址空間大小.超過這個空間大小,核心會根據超過的嚴重程度返回傳送不同的訊號給程序.

注意:決定程序能夠訪問的有效位址空間大小的因素是檔案中被對映的部分,而不是整個檔案;另外,如果指定了檔案的偏移部分,一定要注意為頁面大小的整數倍;

總之:採用記憶體對映機制mmap()來實現程序間通訊是很方便的,在應用層上,呼叫介面非常簡單,內部實現機制涉及到了linux的儲存管理以及檔案系統等方面的內用;

Linux記憶體對映 mmap

linux提供了記憶體對映函式mmap,它把檔案內容對映到一段記憶體上 準確說是虛擬記憶體上 通過對這段記憶體的讀取和修改,實現對檔案的讀取和修改,先來看一下mmap的函式宣告 原型 void mmap void addr,size t length,int prot,int flags,int f...

Linux記憶體對映 mmap函式

linux提供了記憶體對映函式mmap,它把檔案內容對映到一段記憶體上 準確說是虛擬記憶體上 通過對這段記憶體的讀取和修改,實現對檔案的讀取和修改,先來看一下mmap的函式宣告 原型 void mmap void addr,size t length,int prot,int flags,int f...

Linux記憶體對映 mmap函式

mmap將乙個檔案或者其它物件對映進記憶體。檔案被對映到多個頁上,如果檔案的大小不是所有頁的大小之和,最後乙個頁不被使用的空間將會清零。mmap在使用者空間對映呼叫系統中作用很大。標頭檔案 include函式原型void mmap void start,size t length,int prot,...