1. 程式人生 > >mmap和shm共享記憶體的區別和聯絡

mmap和shm共享記憶體的區別和聯絡

共享記憶體的建立

根據理論:

 1. 共享記憶體允許兩個或多個程序共享一給定的儲存區,因為資料不需要來回複製,所以是最快的一種程序間通訊機制。共享記憶體可以通過mmap()對映普通檔案(特殊情況下還可以採用匿名對映)機制實現,也可以通過系統V共享記憶體機制實現。應用介面和原理很簡單,內部機制複雜。為了實現更安全通訊,往往還與訊號燈等同步機制共同使用。

mmap的機制如:就是在磁碟上建立一個檔案,每個程序儲存器裡面,單獨開闢一個空間來進行對映。如果多程序的話,那麼不會對實際的物理儲存器(主存)消耗太大。


shm的機制:每個程序的共享記憶體都直接對映到實際物理儲存器裡面。


結論:

1、mmap儲存到實際硬碟,實際儲存並沒有反映到主存上。優點:儲存量可以很大(多於主存)(這裡一個問題,需要高手解答,會不會太多拷貝到主存裡面???);缺點:程序間讀取和寫入速度要比主存的要慢。


2、shm儲存到物理儲存器(主存),實際的儲存量直接反映到主存上。優點,程序間訪問速度(讀寫)比磁碟要快;缺點,儲存量不能非常大(多於主存)

使用上看:如果分配的儲存量不大,那麼使用shm;如果儲存量大,那麼使用shm。



參看百度:http://baike.baidu.com/view/1499209.htm

mmap就是一個檔案操作

看這些百度的描述:

mmap()系統呼叫使得程序之間通過對映同一個普通檔案實現共享記憶體。普通檔案被對映到程序地址空間後,程序可以向訪問普通記憶體一樣對檔案進行訪問,不必再呼叫read(),write()等操作。 成功執行時,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:試著訪問不屬於程序的記憶體區引數fd為即將對映到程序空間的檔案描述字,

一般由open()返回,同時,fd可以指定為-1,此時須指定 flags引數中的MAP_ANON,表明進行的是匿名對映(不涉及具體的檔名,避免了檔案的建立及開啟,很顯然只能用於具有親緣關係的程序間通訊)

相關文章參考:

mmap函式是unix/linux下的系統呼叫,來看《Unix Netword programming》卷二12.2節有詳細介紹。 mmap系統呼叫並不是完全為了用於共享記憶體而設計的。它本身提供了不同於一般對普通檔案的訪問方式,程序可以像讀寫記憶體一樣對普通檔案的操作。而Posix或系統V的共享記憶體IPC則純粹用於共享目的,當然mmap()實現共享記憶體也是其主要應用之一。

          mmap系統呼叫使得程序之間通過對映同一個普通檔案實現共享記憶體。普通檔案被對映到程序地址空間後,程序可以像訪問普通記憶體一樣對檔案進行訪問,不必再 呼叫read(),write()等操作。mmap並不分配空間, 只是將檔案對映到呼叫程序的地址空間裡, 然後你就可以用memcpy等操作寫檔案, 而不用write()了.寫完後用msync()同步一下, 你所寫的內容就儲存到檔案裡了. 不過這種方式沒辦法增加檔案的長度, 因為要對映的長度在呼叫mmap()的時候就決定了.

簡單說就是把一個檔案的內容在記憶體裡面做一個映像,記憶體比磁碟快些。
基本上它是把一個檔案對應到你的virtual memory 中的一段,並傳回一個指標。

重寫總結:

1、mmap實際就是操作“檔案”。

2、對映檔案,除了主存的考慮外。shm的記憶體共享,效率應該比mmap效率要高(mmap通過io和檔案操作,或“需要寫完後用msync()同步一下”);當然mmap對映操作檔案,比直接操作檔案要快些;由於多了一步msync應該可以說比shm要慢了吧???

3、另一方面,mmap的優點是,操作比shm簡單(沒有呼叫比shm函式複雜),我想這也是許多人喜歡用的原因,包括nginx。

缺點,還得通過實際程式測試,確定!!!

修正理解(這也真是的,這個網站沒辦法附加;只能重寫了):

今天又細心研究了一下,發現百度這麼一段說明:

2、系統呼叫mmap()用於共享記憶體的兩種方式: 
(1)使用普通檔案提供的記憶體對映:適用於任何程序之間;此時,需要開啟或建立一個檔案,然後再呼叫mmap();典型呼叫程式碼如下: 
fd=open(name, flag, mode); 
if(fd<0) 
... 
ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0); 通過mmap()實現共享記憶體的通訊方式有許多特點和要注意的地方,我們將在範例中進行具體說明。 
(2)使用特殊檔案提供匿名記憶體對映:適用於具有親緣關係的程序之間;由於父子程序特殊的親緣關係,在父程序中先呼叫mmap(),然後呼叫fork()。那麼在呼叫fork()之後,子程序繼承父程序匿名對映後的地址空間,同樣也繼承mmap()返回的地址,這樣,父子程序就可以通過對映區域進行通訊了。注意,這裡不是一般的繼承關係。一般來說,子程序單獨維護從父程序繼承下來的一些變數。而mmap()返回的地址,卻由父子程序共同維護。

記憶體對映檔案與虛擬記憶體有些類似,通過記憶體對映檔案可以保留一個地址空間的區域,同時將物理儲存器提交給此區域,只是記憶體檔案對映的物理儲存器來自一個已經存在於磁碟上的檔案,而非系統的頁檔案,而且在對該檔案進行操作之前必須首先對檔案進行對映,就如同將整個檔案從磁碟載入到記憶體。由此可以看出,使用記憶體對映檔案處理儲存於磁碟上的檔案時,將不必再對檔案執行I/O操作,這意味著在對檔案進行處理時將不必再為檔案申請並分配快取,所有的檔案快取操作均由系統直接管理,由於取消了將檔案資料載入到記憶體、資料從記憶體到檔案的回寫以及釋放記憶體塊等步驟,使得記憶體對映檔案在處理大資料量的檔案時能起到相當重要的作用。另外,實際工程中的系統往往需要在多個程序之間共享資料,如果資料量小,處理方法是靈活多變的,如果共享資料容量巨大,那麼就需要藉助於記憶體對映檔案來進行。實際上,記憶體對映檔案正是解決本地多個程序間資料共享的最有效方法。

這裡再總結一次:

1、mmap有兩種方式,一種是對映記憶體,它把普通檔案對映為實際實體記憶體頁,訪問它就和訪問實體記憶體一樣(這也就和shm的功能一樣了)(同時不用重新整理到檔案)

2、mmap可以對映檔案,不確定會不會像windows“記憶體對映檔案”一樣的功能,如果是,那麼他就能對映好幾G甚至好幾百G的記憶體資料,對大資料處理將提供強大功能了???

3、shm只做記憶體對映,和mmap第一個功能一樣!只不過不是普通檔案而已,但都是實體記憶體。