2011-06-02 41 views
8

我正面臨一種情況,我需要從一個進程傳遞數百兆內存。現在我正在通過文件來做,而且速度太慢。 我想爲了讓它更快,這些文件應該直接寫入RAM,並可以從另一個進程訪問。沒有花哨的同步需要。一個進程將創建共享內存對象並將其填充數據。另一個進程會讀取並刪除它們。然而,我已經做了一個快速的研究,看起來你不能在Windows的RAM中共享內存 - 共享內存由文件或分頁文件支持。 boost :: interprocess的文檔證實了這一點。如果共享內存實現仍在使用磁盤,那麼速度在哪裏呢?是否有任何使用基於RAM的共享內存的C++庫?在C++中尋找Windows基於RAM的共享內存解決方案

編輯:我做了一些擴展閱讀: 1.從boost ::進程間文檔: 「作爲操作系統具有對文件內容與內存同步的內容,內存映射文件是不一樣快的共享內存「 2. from http://msdn.microsoft.com/en-us/library/ms810613.aspx: 」內存映射文件也可以同時被多個應用程序映射,這代表了兩個或多個進程在Windows NT中直接共享數據的唯一機制。「

+0

Windows中的所有內存都由文件支持,就像任何虛擬內存操作系統一樣。文件由內存(文件系統緩存)支持。這使得你很可能看不到加速。這應該在RAM總線速度下移動,對於DDR2〜5GB/sec。 – 2011-06-02 02:49:05

+0

@Hans:你是否說使用共享內存不會讓我有任何提高速度,而不是直接將數據保存到磁盤文件? – andriej 2011-06-02 08:21:57

+0

也許提升Windows共享內存將成爲你的衚衕。這是非持續性的,如果這就是你的真正意思。 http://www.boost.org/doc/libs/1_35_0/doc/html/boost/interprocess/windows_shared_memory.html – 2013-06-01 15:59:57

回答

13

我認爲這裏是一個根本性的誤解:你認爲,如果你創建的備份文件映射分頁文件,它會像在磁盤上寫東西一樣慢。

這絕對不是這種情況:文檔中「由分頁文件支持」的含義意味着共享內存通常駐留在內存中,但在分頁文件中有一個保留位置用於寫入此類數據沒有足夠的可用物理內存,虛擬內存管理器需要交換內存頁面。

這不是從文檔是很清楚,但File Mapping頁面上MSDN證實:

[...]它是由磁盤上的文件備份。這意味着當系統換出文件映射對象的頁面時,對文件映射對象所做的任何更改都將寫入該文件。當文件映射對象的頁面交換回來時,它們將從文件中恢復。

請注意,這適用於由頁面文件支持的共享內存以及由常規文件支持的內存(VMM保證各種視圖保持一致)。順便提一下,這是用戶進程中「常規」(=虛擬)內存的工作方式:如果當前未使用分配內存的每個位都可以換出到分頁文件,並且系統需要爲其他內存使用物理內存東西(例如,使當前使用的內存頁面可用於您的/另一個應用程序)。

+4

+1試圖解決OP的誤解。 – 0xC0000022L 2011-06-02 13:43:11

6

沒有什麼錯是通過一個文件備份 - 內存壓力下,數據必須去的地方,你的選擇是:

  • 把內存作爲神聖的數據不能被分頁或丟棄

    可能只會造成更糟的內存壓力問題,但是對於某些嵌入式系統來說,這是一個很好的選擇,因爲系統的整個運行時環境都可以很好地控制。

  • 降的存儲器

    顯然不適合於所有的數據。緩存的內容?也許。原始照片?可能不會。

  • 頁的內存,磁盤

    好通用的選擇!

使用共享內存工具時,您是否看到內存壓力?添加更多內存或找出如何縮小您的系統。 :)

+0

@sarnoid:您錯過了這一點。當內存壓力過大時,我不在乎Windows的內存是否被Windows寫入磁盤。我想避免磁盤文件和RAM之間的同步,不管內存壓力如何,都會發生同步 - 據我所知,這是Windows共享內存的實現方式? – andriej 2011-06-02 09:37:33

+0

據我所知,只有在內存壓力下,共享內存纔會真正移動到分頁文件中,順便說一句,用戶進程的每一點內存都會發生什麼情況。 – 2011-06-02 13:31:47

+0

@ user467799:呵?然後使用由頁面文件支持的MMF。有什麼大不了的? NT中的頁面編寫器是一個懶惰的頁面編寫器。這意味着只有在絕對必要時纔會將頁面寫入磁盤(過於簡化但接近)。所以只是不要冒汗。有了足夠的內存,您不會看到任何性能下降。 – 0xC0000022L 2011-06-02 13:35:41

3

據我所知你基本上有2選項在這裏。

1)您創建一個DLL並使用data_seg編譯指示並在您的兩個進程中加載​​DLL。這有它在這裏詳細解釋巨大的缺點: http://msdn.microsoft.com/en-us/library/h90dkhs0(v=vs.80).aspx

最重要的缺點是:空間已被靜態初始化並存儲在編譯的DLL的數據段,這意味着如果你想分享數百的MB使用這種方法,那麼你的DLL將成爲數百MB大。

2)使用普通的內存映射文件沒什麼問題,儘管它們被緩存了。你甚至可以使用系統頁面文件來存儲數據,在這篇文章中描述: http://msdn.microsoft.com/en-us/library/ms810613.aspx

我實際測試過這個例子的進程間通信 隨着1吉布內存映射文件的[1],可以確認什麼甚至在用數據填充整個GiB之後被寫入磁盤。

[1] http://msdn.microsoft.com/en-us/library/aa366551(v=vs.85).aspx

+0

「使用常規的內存映射文件沒有什麼問題」 - 從我讀的內容來看,它們並不是我需要的最快解決方案,因爲它們暗示着磁盤I/O,而純粹的基於RAM的共享內存並不總是意味着交換到磁盤。 – andriej 2011-06-02 10:16:00

+1

@ user467799:不真實。確實可以有I/O,但這完全取決於緩存管理器。如果您使用頁面文件支持的MMF並擁有足夠的RAM,則基本上不會有開銷。作爲獎勵,您的程序可能仍會在受限制的情況下運行 - 儘管性能下降。如果你要使用堆內存,情況並非如此。 – 0xC0000022L 2011-06-02 13:33:30

1

我還是會建議內存映射文件,而不是我會提到的辦法。

如果您真的想從另一個進程內存中讀取,請使用Win32 API ReadProcessMemory()

如果你是在保持數據存儲在RAM偏執,有Unix的m鎖()等同於微軟Windows VirtualLock()

+0

正如文章指出「ReadProcessMemory複製數據」並且實際上不會給他共享內存,這將允許他做他想做的事:「其他進程將讀取並刪除它們」。他必須打電話給第一個流程才能刪除它,因爲他無法寫信給它。 – PeterT 2011-06-02 14:37:33