mmap的用法

1 mmap概述

mmap將一個文件或者其它對象映射進內存的系統函數。文件被映射到多個頁上,若是文件的大小不是全部頁的大小之和,最後一個頁不被使用的空間將會清零。mmap在用戶空間映射調用系統中做用很大。函數

頭文件 <sys/mman.h>性能

函數原型spa

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

int munmap(void* start,size_t length);指針

參數詳解:htm

1 void *start 映射區的開始地址,設置爲0時表示由系統決定映射區的起始地址。對象

2 size_t length 映射區的長度。//長度單位是 以字節爲單位,不足一內存頁按一內存頁處理繼承

3 int prot 指望的內存保護標誌,不能與文件的打開模式衝突。是如下的某個值,能夠經過or運算合理地組合在一塊兒進程


PROT_EXEC
頁內容能夠被執行
PROT_READ 頁內容能夠被讀取
PROT_WRITE 頁能夠被寫入
PROT_NONE
頁不可訪問

4 int 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一塊兒使用時纔有意義。不執行預讀,只爲已存在於內存中的頁面創建頁表入口。

5 int fd 有效的文件描述符,通常是由open()函數返回,其值也能夠設置爲-1,此時須要指定flags參數中的MAP_ANON,代表進行的是匿名映射。

6 off_t offset  被映射對象內容的起點

返回值說明:

成功執行時,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:試着訪問不屬於進程的內存區

2 mmap對設備操做

mmap操做提供了一種機制,讓用戶程序直接訪問設備內存,這種機制,相比較在用戶空間內核空間互相拷貝數據,效率更高。在要求高性能的應用中比較經常使用。mmap映射內存必須是頁面大小的整數倍,面向流的設備不能進行mmap,mmap的實現和硬件有關。


3 mmap系統調用詳解

mmap()系統調用使得進程之間經過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間後,進程能夠像訪問普通內存同樣對文件進行訪問,沒必要再調用read(),write()等操做。

注:實際上,mmap()系統調用並非徹底爲了用於共享內存而設計的。它自己提供了不一樣於通常對普通文件的訪問方式,進程能夠像讀寫內存同樣對普通文件 的操做。而Posix或系統V的共享內存IPC則純粹用於共享目的,固然mmap()實現共享內存也是其主要應用之一。

3.1 參數的慣經常使用法

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

參數fd爲即將映射到進程空間的文件描述字,通常由open()返回,同時,fd能夠指定爲-1,此時須指定flags參數中的MAP_ANON,代表進 行的是匿名映射(不涉及具體的文件名,避免了文件的建立及打開,很顯然只能用於具備親緣關係的進程間通訊)。len是映射到調用進程地址空間的字節數,它 從被映射文件開頭offset個字節開始算起。prot 參數指定共享內存的訪問權限。可取以下幾個值的或:PROT_READ(可讀) , PROT_WRITE (可寫), PROT_EXEC (可執行), PROT_NONE(不可訪問)。flags由如下幾個常值指定:MAP_SHARED , MAP_PRIVATE , MAP_FIXED,其中,MAP_SHARED , MAP_PRIVATE必選其一,而MAP_FIXED則不推薦使用。offset參數通常設爲0,表示從文件頭開始映射。參數addr指定文件應被映射 到進程空間的起始地址,通常被指定一個空指針,此時選擇起始地址的任務留給內核來完成。函數的返回值爲最後文件映射到進程空間的地址,進程可直接操做起始 地址爲該值的有效地址。

3.2  系統調用mmap()用於共享內存的兩種方式:

3.2.1 使用普通文件提供的內存映射

適用於任何進程之間;此時,須要打開或建立一個文件,而後再調用mmap();典型調用代碼以下:
  fd=open(name, flag, mode);
  if(fd<0)
  ...
  ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0); 經過mmap()實現共享內存的通訊方式有許多特色和要注意的地方,咱們將在範例中進行具體說明。

3.2.2 使用特殊文件提供匿名內存映射

適用於具備親緣關係的進程之間;因爲父子進程特殊的親緣關係,在父進程中先調用mmap(),而後調用fork()。那麼在調用fork()以後,子進程 繼承父進程匿名映射後的地址空間,一樣也繼承mmap()返回的地址,這樣,父子進程就能夠經過映射區域進行通訊了。注意,這裏不是通常的繼承關係。通常 來講,子進程單獨維護從父進程繼承下來的一些變量。而mmap()返回的地址,卻由父子進程共同維護。   對於具備親緣關係的進程實現共享內存最好的方式應該是採用匿名內存映射的方式。此時,沒必要指定具體的文件,只要設置相應的標誌便可,參見範例2。

3.3 相關的系統調用

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

int msync ( void * addr , size_t len, int flags)
  通常說來,進程在映射空間的對共享內容的改變並不直接寫回到磁盤文件中,每每在調用munmap()後才執行該操做。能夠經過調用msync()實現磁盤上文件內容與共享內存區的內容一致。

4 動手實戰

兩個進程間映射普通文件實現共享內存通訊。

相關文章
相關標籤/搜索