Linux系統(tǒng)調用-- mmap/munmap函數 (詳細講解~)
功能描述: mmap將一個文件或者其它對象映射進內存。文件被映射到多個頁上,如果文件的大小不是所有頁的大小之和,最后一個頁不被使用的空間將會清零。munmap執(zhí)行相反的操作,刪除特定地址區(qū)域的對象映射。 基 于文件的映射,在mmap和munmap執(zhí)行過程的任何時刻,被映射文件的st_atime可能被更新。如果st_atime字段在前述的情況下沒有得到 更新,首次對映射區(qū)的第一個頁索引時會更新該字段的值。用PROT_WRITE 和 MAP_SHARED標志建立起來的文件映射,其st_ctime和 st_mtime在對映射區(qū)寫入之后,但在msync()通過MS_SYNC 和 MS_ASYNC兩個標志調用之前會被更新。 用法: ?
參數: ?
start:映射區(qū)的開始地址。
length:映射區(qū)的長度。
prot:期望的內存保護標志,不能與文件的打開模式沖突。是以下的某個值,可以通過or運算合理地組合在一起
PROT_EXEC //頁內容可以被執(zhí)行
PROT_READ ?//頁內容可以被讀取
PROT_WRITE //頁可以被寫入
PROT_NONE ?//頁不可訪問
flags:指定映射對象的類型,映射選項和映射頁是否可以共享。它的值可以是一個或者多個以下位的組合體
MAP_FIXED //使用指定的映射起始地址,如果由start和len參數指定的內存區(qū)重疊于現(xiàn)存的映射空間,重疊部分將會被丟棄。如果指定的起始地址不可用,操作將會失敗。并且起始地址必須落在頁的邊界上。
MAP_SHARED //與其它所有映射這個對象的進程共享映射空間。對共享區(qū)的寫入,相當于輸出到文件。直到msync()或者munmap()被調用,文件實際上不會被更新。
MAP_PRIVATE //建立一個寫入時拷貝的私有映射。內存區(qū)域的寫入不會影響到原文件。這個標志和以上標志是互斥的,只能使用其中一個。
MAP_DENYWRITE //這個標志被忽略。
MAP_EXECUTABLE //同上
MAP_NORESERVE //不要為這個映射保留交換空間。當交換空間被保留,對映射區(qū)修改的可能會得到保證。當交換空間不被保留,同時內存不足,對映射區(qū)的修改會引起段違例信號。
MAP_LOCKED //鎖定映射區(qū)的頁面,從而防止頁面被交換出內存。
MAP_GROWSDOWN //用于堆棧,告訴內核VM系統(tǒng),映射區(qū)可以向下擴展。
MAP_ANONYMOUS //匿名映射,映射區(qū)不與任何文件關聯(lián)。
MAP_ANON //MAP_ANONYMOUS的別稱,不再被使用。
MAP_FILE //兼容標志,被忽略。
MAP_32BIT //將映射區(qū)放在進程地址空間的低2GB,MAP_FIXED指定時會被忽略。當前這個標志只在x86-64平臺上得到支持。
MAP_POPULATE //為文件映射通過預讀的方式準備好頁表。隨后對映射區(qū)的訪問不會被頁違例阻塞。
MAP_NONBLOCK //僅和MAP_POPULATE一起使用時才有意義。不執(zhí)行預讀,只為已存在于內存中的頁面建立頁表入口。
fd:有效的文件描述詞。如果MAP_ANONYMOUS被設定,為了兼容問題,其值應為-1。
offset:被映射對象內容的起點。
返回說明: ? 成功執(zhí)行時,mmap()返回被映射區(qū)的指針,munmap()返回0。失敗時,mmap()返回MAP_FAILED[其值為(void *)-1],munmap返回-1。errno被設為以下的某個值 ? EACCES:訪問出錯 EAGAIN:文件已被鎖定,或者太多的內存已被鎖定 EBADF:fd不是有效的文件描述詞 EINVAL:一個或者多個參數無效 ENFILE:已達到系統(tǒng)對打開文件的限制 ENODEV:指定文件所在的文件系統(tǒng)不支持內存映射 ENOMEM:內存不足,或者進程已超出最大內存映射數量 EPERM:權能不足,操作不允許 ETXTBSY:已寫的方式打開文件,同時指定MAP_DENYWRITE標志 SIGSEGV:試著向只讀區(qū)寫入 SIGBUS:試著訪問不屬于進程的內存區(qū) mmap系統(tǒng)調用并不是完全為了用于共享內存而設計的。它本身提供了不同于一般對普通文件的訪問方式,進程可以像讀寫內存一樣對普通文件的操作。而Posix或系統(tǒng)V的共享內存IPC則純粹用于共享目的,當然mmap()實現(xiàn)共享內存也是其主要應用之一。 ? ? ? ? ?mmap系統(tǒng)調用使得進程之間通過映射同一個普通文件實現(xiàn)共享內存。普通文件被映射到進程地址空間后,進程可以像訪問普通內存一樣對文件進行訪問,不必再 調用read(),write()等操作。mmap并不分配空間, 只是將文件映射到調用進程的地址空間里, 然后你就可以用memcpy等操作寫文件, 而不用write()了.寫完后用msync()同步一下, 你所寫的內容就保存到文件里了. 不過這種方式沒辦法增加文件的長度, 因為要映射的長度在調用mmap()的時候就決定了. 簡單說就是把一個文件的內容在內存里面做一個映像,內存比磁盤快些。 基本上它是把一個檔案對應到你的virtual memory 中的一段,并傳回一個指針。 以后對這段 memory 做存取時,其實就是對那個檔做存取。 它就是一種快速 file I/O 的東東,而且使用上和存取 memory 一樣方便,只不過會占掉你的 virutal memory。
【文章福利】小編推薦自己的Linux內核技術交流群:【891587639】整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)?


mmap開啟記憶體對映。
參數fd為即將映射到進程空間的文件描述字,一般由open()返回,同時,fd可以指定為-1,此時須指定flags參數中的MAP_ANON,表明進行的是匿名映射(不涉及具體的文件名,避免了文件的創(chuàng)建及打開,很顯然只能用于具有親緣關系的進程間通信)。
len是映射到調用進程地址空間的字節(jié)數,它從被映射文件開頭offset個字節(jié)開始算起。
prot參數指定共享內存的訪問權限。可取如下幾個值的或:PROT_READ(可讀),PROT_WRITE(可寫),PROT_EXEC(可執(zhí)行),PROT_NONE(不可訪問)。
flags由以下幾個常值指定:MAP_SHARED, MAP_PRIVATE, MAP_FIXED。其中,MAP_SHARED,MAP_PRIVATE必選其一,而MAP_FIXED則不推薦使用。 如果指定為 MAP_SHARED,則對映射的內存所做的修改同樣影響到文件。如果是MAP_PRIVATE,則對映射的內存所做的修改僅對該進程可見,對文件沒有影 響。
offset參數一般設為0,表示從文件頭開始映射。
int munmap(void *start, size_t length);
int msync(const void *start, size_t length, int flags);
如果開啟記憶體對映是希望寫入檔案中,那麼修改過的記憶體會在一段時間內與檔案稍稍有點不同。如果您希望立即將資料寫入檔案中,可使用msync。
start為記憶體開始位置,length為長度。
flags則有三個:
MS_ASYNC : 請Kernel快將資料寫入。
MS_SYNC : 在msync結束返回前,將資料寫入。
MS_INVALIDATE : 讓核心自行決定是否寫入,僅在特殊狀況下使用
例子:功能描述:
mmap將一個文件或者其它對象映射進內存。文件被映射到多個頁上,如果文件的大小不是所有頁的大小之和,最后一個頁不被使用的空間將會清零。munmap執(zhí)行相反的操作,刪除特定地址區(qū)域的對象映射。
基 于文件的映射,在mmap和munmap執(zhí)行過程的任何時刻,被映射文件的st_atime可能被更新。如果st_atime字段在前述的情況下沒有得到 更新,首次對映射區(qū)的第一個頁索引時會更新該字段的值。用PROT_WRITE 和 MAP_SHARED標志建立起來的文件映射,其st_ctime和 st_mtime在對映射區(qū)寫入之后,但在msync()通過MS_SYNC 和 MS_ASYNC兩個標志調用之前會被更新。
用法: ?
參數: ?
start:映射區(qū)的開始地址。
length:映射區(qū)的長度。
prot:期望的內存保護標志,不能與文件的打開模式沖突。是以下的某個值,可以通過or運算合理地組合在一起
PROT_EXEC //頁內容可以被執(zhí)行
PROT_READ ?//頁內容可以被讀取
PROT_WRITE //頁可以被寫入
PROT_NONE ?//頁不可訪問
flags:指定映射對象的類型,映射選項和映射頁是否可以共享。它的值可以是一個或者多個以下位的組合體
MAP_FIXED //使用指定的映射起始地址,如果由start和len參數指定的內存區(qū)重疊于現(xiàn)存的映射空間,重疊部分將會被丟棄。如果指定的起始地址不可用,操作將會失敗。并且起始地址必須落在頁的邊界上。
MAP_SHARED //與其它所有映射這個對象的進程共享映射空間。對共享區(qū)的寫入,相當于輸出到文件。直到msync()或者munmap()被調用,文件實際上不會被更新。
MAP_PRIVATE //建立一個寫入時拷貝的私有映射。內存區(qū)域的寫入不會影響到原文件。這個標志和以上標志是互斥的,只能使用其中一個。
MAP_DENYWRITE //這個標志被忽略。
MAP_EXECUTABLE //同上
MAP_NORESERVE //不要為這個映射保留交換空間。當交換空間被保留,對映射區(qū)修改的可能會得到保證。當交換空間不被保留,同時內存不足,對映射區(qū)的修改會引起段違例信號。
MAP_LOCKED //鎖定映射區(qū)的頁面,從而防止頁面被交換出內存。
MAP_GROWSDOWN //用于堆棧,告訴內核VM系統(tǒng),映射區(qū)可以向下擴展。
MAP_ANONYMOUS //匿名映射,映射區(qū)不與任何文件關聯(lián)。
MAP_ANON //MAP_ANONYMOUS的別稱,不再被使用。
MAP_FILE //兼容標志,被忽略。
MAP_32BIT //將映射區(qū)放在進程地址空間的低2GB,MAP_FIXED指定時會被忽略。當前這個標志只在x86-64平臺上得到支持。
MAP_POPULATE //為文件映射通過預讀的方式準備好頁表。隨后對映射區(qū)的訪問不會被頁違例阻塞。
MAP_NONBLOCK //僅和MAP_POPULATE一起使用時才有意義。不執(zhí)行預讀,只為已存在于內存中的頁面建立頁表入口。
fd:有效的文件描述詞。如果MAP_ANONYMOUS被設定,為了兼容問題,其值應為-1。
offset:被映射對象內容的起點。
返回說明: ?
成功執(zhí)行時,mmap()返回被映射區(qū)的指針,munmap()返回0。失敗時,mmap()返回MAP_FAILED[其值為(void *)-1],munmap返回-1。errno被設為以下的某個值 ?
EACCES:訪問出錯
EAGAIN:文件已被鎖定,或者太多的內存已被鎖定
EBADF:fd不是有效的文件描述詞
EINVAL:一個或者多個參數無效
ENFILE:已達到系統(tǒng)對打開文件的限制
ENODEV:指定文件所在的文件系統(tǒng)不支持內存映射
ENOMEM:內存不足,或者進程已超出最大內存映射數量
EPERM:權能不足,操作不允許
ETXTBSY:已寫的方式打開文件,同時指定MAP_DENYWRITE標志
SIGSEGV:試著向只讀區(qū)寫入
SIGBUS:試著訪問不屬于進程的內存區(qū)
mmap系統(tǒng)調用并不是完全為了用于共享內存而設計的。它本身提供了不同于一般對普通文件的訪問方式,進程可以像讀寫內存一樣對普通文件的操作。而Posix或系統(tǒng)V的共享內存IPC則純粹用于共享目的,當然mmap()實現(xiàn)共享內存也是其主要應用之一。
? ? ? ? ?mmap系統(tǒng)調用使得進程之間通過映射同一個普通文件實現(xiàn)共享內存。普通文件被映射到進程地址空間后,進程可以像訪問普通內存一樣對文件進行訪問,不必再 調用read(),write()等操作。mmap并不分配空間, 只是將文件映射到調用進程的地址空間里, 然后你就可以用memcpy等操作寫文件, 而不用write()了.寫完后用msync()同步一下, 你所寫的內容就保存到文件里了. 不過這種方式沒辦法增加文件的長度, 因為要映射的長度在調用mmap()的時候就決定了.
簡單說就是把一個文件的內容在內存里面做一個映像,內存比磁盤快些。
基本上它是把一個檔案對應到你的virtual memory 中的一段,并傳回一個指針。
以后對這段 memory 做存取時,其實就是對那個檔做存取。
它就是一種快速 file I/O 的東東,而且使用上和存取 memory 一樣方便,只不過會占掉你的 virutal memory。
mmap開啟記憶體對映。 參數fd為即將映射到進程空間的文件描述字,一般由open()返回,同時,fd可以指定為-1,此時須指定flags參數中的MAP_ANON,表明進行的是匿名映射(不涉及具體的文件名,避免了文件的創(chuàng)建及打開,很顯然只能用于具有親緣關系的進程間通信)。 len是映射到調用進程地址空間的字節(jié)數,它從被映射文件開頭offset個字節(jié)開始算起。 prot參數指定共享內存的訪問權限??扇∪缦聨讉€值的或:PROT_READ(可讀),PROT_WRITE(可寫),PROT_EXEC(可執(zhí)行),PROT_NONE(不可訪問)。 flags由以下幾個常值指定:MAP_SHARED, MAP_PRIVATE, MAP_FIXED。其中,MAP_SHARED,MAP_PRIVATE必選其一,而MAP_FIXED則不推薦使用。 如果指定為 MAP_SHARED,則對映射的內存所做的修改同樣影響到文件。如果是MAP_PRIVATE,則對映射的內存所做的修改僅對該進程可見,對文件沒有影 響。 offset參數一般設為0,表示從文件頭開始映射。 int munmap(void *start, size_t length); int msync(const void *start, size_t length, int flags); 如果開啟記憶體對映是希望寫入檔案中,那麼修改過的記憶體會在一段時間內與檔案稍稍有點不同。如果您希望立即將資料寫入檔案中,可使用msync。 start為記憶體開始位置,length為長度。 flags則有三個: MS_ASYNC : 請Kernel快將資料寫入。 MS_SYNC : 在msync結束返回前,將資料寫入。 MS_INVALIDATE : 讓核心自行決定是否寫入,僅在特殊狀況下使用?
例子:
mmap()及其相關系統(tǒng)調用
mmap()系統(tǒng)調用使得進程之間通過映射同一個普通文件實現(xiàn)共享內存。普通文件被映射到進程地址空間后,進程可以向訪問普通內存一樣對文件進行訪問,不必再調用read(),write()等操作。 注:實際上,mmap()系統(tǒng)調用并不是完全為了用于共享內存而設計的。它本身提供了不同于一般對普通文件的訪問方式,進程可以像讀寫內存一樣對普通文件的操作。而Posix或系統(tǒng)V的共享內存IPC則純粹用于共享目的,當然mmap()實現(xiàn)共享內存也是其主要應用之一。 1、mmap()系統(tǒng)調用形式如下: void* mmap ( void * addr , size_t len , int prot , int flags , int fd , off_t offset ) 參數fd為即將映射到進程空間的文件描述字,一般由open()返回,同時,fd可以指定為-1,此時須指定flags參數中的MAP_ANON,表明進 行的是匿名映射(不涉及具體的文件名,避免了文件的創(chuàng)建及打開,很顯然只能用于具有親緣關系的進程間通信)。len是映射到調用進程地址空間的字節(jié)數,它 從被映射文件開頭offset個字節(jié)開始算起。prot 參數指定共享內存的訪問權限??扇∪缦聨讉€值的或:PROT_READ(可讀) , PROT_WRITE (可寫), PROT_EXEC (可執(zhí)行), PROT_NONE(不可訪問)。flags由以下幾個常值指定:MAP_SHARED , MAP_PRIVATE , MAP_FIXED,其中,MAP_SHARED , MAP_PRIVATE必選其一,而MAP_FIXED則不推薦使用。offset參數一般設為0,表示從文件頭開始映射。參數addr指定文件應被映射 到進程空間的起始地址,一般被指定一個空指針,此時選擇起始地址的任務留給內核來完成。函數的返回值為最后文件映射到進程空間的地址,進程可直接操作起始 地址為該值的有效地址。這里不再詳細介紹mmap()的參數,讀者可參考mmap()手冊頁獲得進一步的信息。 2、系統(tǒng)調用mmap()用于共享內存的兩種方式: (1)使用普通文件提供的內存映射:適用于任何進程之間;此時,需要打開或創(chuàng)建一個文件,然后再調用mmap();典型調用代碼如下: fd=open(name, flag, mode); if(fd<0) ... ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0); 通過mmap()實現(xiàn)共享內存的通信方式有許多特點和要注意的地方,我們將在范例中進行具體說明。 (2)使用特殊文件提供匿名內存映射:適用于具有親緣關系的進程之間;由于父子進程特殊的親緣關系,在父進程中先調用mmap(),然后調 用fork()。那么在調用fork()之后,子進程繼承父進程匿名映射后的地址空間,同樣也繼承mmap()返回的地址,這樣,父子進程就可以通過映射 區(qū)域進行通信了。注意,這里不是一般的繼承關系。一般來說,子進程單獨維護從父進程繼承下來的一些變量。而mmap()返回的地址,卻由父子進程共同維 護。 對于具有親緣關系的進程實現(xiàn)共享內存最好的方式應該是采用匿名內存映射的方式。此時,不必指定具體的文件,只要設置相應的標志即可,參見范例2。 3、系統(tǒng)調用munmap() int munmap( void * addr, size_t len ) 該調用在進程地址空間中解除一個映射關系,addr是調用mmap()時返回的地址,len是映射區(qū)的大小。當映射關系解除后,對原來映射地址的訪問將導致段錯誤發(fā)生。 4、系統(tǒng)調用msync() int msync ( void * addr , size_t len, int flags) 一般說來,進程在映射空間的對共享內容的改變并不直接寫回到磁盤文件中,往往在調用munmap()后才執(zhí)行該操作??梢酝ㄟ^調用msync()實現(xiàn)磁盤上文件內容與共享內存區(qū)的內容一致
