【前言】對這兩個理解還是不夠深刻,寫一篇博客來記錄一下。
首先關於共享內存的鏈接:共享內存。里面包含了創建共享內存區域的函數,以及兩個進程怎么掛載共享內存通信,分離、釋放共享內存。
共享內存的好處就是效率高,不需要太多次的進行數據的copy。可以直接進行讀寫內存。所以,相對來說在IPC進程間通信三大主題里面,共享內存要比消息隊列使用多,而且消息隊列只在有血緣關系的進程間通信;但是,共享內存不保證同步,使用了信號量用來保證共享內存同步。Linux中的兩種共享內存。一種是我們的IPC通信System V版本的共享內存,另外的一種就是我們今天提到的存儲映射I/O(mmap函數),當然還有一種POSIX的共享內存,它是在mmap基礎之上構建的。
一、mmap
mmap I/O的描述符間接說明內存映射是對文件操作。另外,mmap另外可以在無親緣的進程之間提供共享內存區。這樣,類似的兩個進程之間就是可以進行了通信。
Linux提供了內存映射函數mmap, 它把文件內容映射到一段內存上(准確說是虛擬內存上,運行着進程), 通過對這段內存的讀取和修改, 實現對文件的讀取和修改。mmap()系統調用使得進程之間可以通過映射一個普通的文件實現共享內存。普通文件映射到進程地址空間后,進程可以像訪問內存的方式對文件進行訪問,不需要其他內核態的系統調用(read,write)去操作。
這里是講設備或者硬盤存儲的一塊空間映射到物理內存,然后操作這塊物理內存就是在操作實際的硬盤空間,不需要經過內核態傳遞。比如你的硬盤上有一個文件,你可以使用linux系統提供的mmap接口,將這個文件映射到進程一塊虛擬地址空間,這塊空間會對應一塊物理內存,當你讀寫這塊物理空間的時候,就是在讀取實際的磁盤文件,就是這么直接高效。通常諸如共享庫的加載都是通過內存映射的方式加載到物理內存的。
mmap系統調用並不完全是為了共享內存來設計的,它本身提供了不同於一般對普通文件的訪問的方式,進程可以像讀寫內存一樣對普通文件進行操作,IPC的共享內存是純粹為了共享。
(1)mmap系統調用介紹:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
這就是mmap系統調用的接口,mmap函數成功返回指向內存區域的指針,失敗返回MAP_FAILED。
addr,某個特定的地址作為起始地址,當被設置為NULL,標識系統自動分配地址。實實在在的物理區域。
length說的是內存段的長度。
prot是用來設定內存段的訪問權限。
| prot參數 | 說明 |
|---|---|
| PROT_READ | 內存段可讀 |
| PROT_WRITE | 內存段可寫 |
| PROT_EXEC | 內存段可執行 |
| PROT_NONE | 內存段不能被訪問 |
flags參數控制內存段內容被修改以后程序的行為。
| flags參數 | 說明 |
|---|---|
| MAP_SHARED | 進程間共享內存,對該內存段修改反映到映射文件中。提供了POSIX共享內存 |
| MAP_PRIVATE | 內存段為調用進程所私有。對該內存段的修改不會反映到映射文件 |
| MAP_ANNOYMOUS | 這段內存不是從文件映射而來的。內容被初始化為全0 |
| MAP_FIXED | 內存段必須位於start參數指定的地址處,start必須是頁大小的整數倍(4K整數倍) |
| MAP_HUGETLB | 按照大內存頁面來分配內存空間 |
fd參數是用來被映射文件對應的文件描述符。通過open系統調用得到。
offset設定從何處進行映射。
(2)mmap用於共享內存的方式
1、我們可以使用普通文件進行提供內存映射,例如,open系統調用打開一個文件,然后進行mmap操作,得到共享內存,這種方式適用於任何進程之間。
2、可以使用特殊文件進行匿名內存映射,這個相對的是具有血緣關系的進程之間,當父進程調用mmap,然后進行fork,這樣父進程創建的子進程會繼承父進程匿名映射后的地址空間,這樣,父子進程之間就可以進行通信了。相當於是mmap的返回地址此時是父子進程同時來維護。
3、另外POSIX版本的共享內存底層也是使用了mmap。所以,共享內存在在posix上一定程度上就是指的內存映射了。https://www.cnblogs.com/LubinLew/p/POSIX-shared_memory.html
三、mmap和System V共享內存的比較
共享內存:
![![enter description here][1]](/image/aHR0cHM6Ly9pbWctYmxvZy5jc2RuLm5ldC8yMDE3MDMyODE1MjE0MTA4Nz93YXRlcm1hcmsvMi90ZXh0L2FIUjBjRG92TDJKc2IyY3VZM05rYmk1dVpYUXZjWEZmTWpZM05qZzNOREU9L2ZvbnQvNWE2TDVMMlQvZm9udHNpemUvNDAwL2ZpbGwvSTBKQlFrRkNNQT09L2Rpc3NvbHZlLzcwL2dyYXZpdHkvU291dGhFYXN0.png)
這是System V版本的共享內存(以下我們統稱為shm),下面看下mmap的:![![enter description here][2]](/image/aHR0cHM6Ly9pbWctYmxvZy5jc2RuLm5ldC8yMDE3MDMyODE1MjIxODYyMD93YXRlcm1hcmsvMi90ZXh0L2FIUjBjRG92TDJKc2IyY3VZM05rYmk1dVpYUXZjWEZmTWpZM05qZzNOREU9L2ZvbnQvNWE2TDVMMlQvZm9udHNpemUvNDAwL2ZpbGwvSTBKQlFrRkNNQT09L2Rpc3NvbHZlLzcwL2dyYXZpdHkvU291dGhFYXN0.png)
總結:
1、mmap是在磁盤上建立一個文件,每個進程地址空間中開辟出一塊空間進行映射。而shm共享內存,每個進程最終會映射到同一塊物理內存。shm保存在物理內存,這樣讀寫的速度肯定要比磁盤要快,但是存儲量不是特別大。
2、相對於shm來說,mmap更加簡單,調用更加方便,所以這也是大家都喜歡用的原因。
3、另外mmap有一個好處是當機器重啟,因為mmap把文件保存在磁盤上,這個文件還保存了操作系統同步的映像,所以mmap不會丟失,但是shmget在內存里面就會丟失。
4、總之,共享內存是在內存中創建空間,每個進程映射到此處。內存映射是創建一個文件,並且映射到每個進程開辟的空間中。
但在posix中的共享內存就是指這種使用文件的方式“內存映射”。參考:https://www.cnblogs.com/LubinLew/p/POSIX-shared_memory.html
附錄:linux高端內存https://www.cnblogs.com/wuchanming/p/4360277.html
