我是使用基於Linux的服務器開發多人在線遊戲的程序員。我們爲我們的世界使用「實例化」架構。這意味着每個進入世界區域的玩家都會得到該區域的副本,與其隊員一起玩,並且獨立於在同一區域玩的所有其他玩家。更高效地使用fork()和寫入時複製內存共享
在內部,我們對每個實例使用單獨的進程。最初,每個實例進程將啓動,僅加載給定區域所需的資源,生成隨機地形,然後允許來自玩家的新連接。實例使用的內存量通常約爲25兆字節,其中包括資源和隨機生成的實體級別。
爲了減少實例的內存佔用,並加快產卵時間,我們改變了一種方法,我們創建一個主實例,加載所有實例可能需要的所有資源(大約150兆內存),然後在需要新實例時,使用fork()函數生成一個新實例並利用寫時複製內存共享,以便新實例僅爲其「唯一」數據集提供內存。隨機生成的關卡和組成每個實例的唯一數據的實體大小約爲3-4兆內存。
不幸的是,內存共享不像我想的那樣工作得很好。很多內存頁面似乎都沒有共享。首先,當我們在prefork實例中加載更多的數據集時,每個分叉實例所需的內存都會減少,但最終會出現一個轉折點,在prefork中加載更多資源實際上增加了使用的數據每個分叉的實例。
我們得到的最好結果是加載大約80兆數據集前叉,然後讓新的實例需要加載餘下的部分。這導致每個實例大約7-10個額外的兆字節和80兆個固定成本。當然是一個很好的改進,但不是理論上最好的。
如果我加載整個150兆數據集,然後分叉,每個分叉實例使用大約50多兆內存!比單純無所事事顯得更糟。
我的問題是,如何將所有數據集加載到prefork實例中,並確保我只獲取每個實例的最小唯一真實數據集作爲每個實例的內存佔用空間。
我對這裏發生了什麼有一個理論,我想知道是否有人能夠幫助確認這是事實。
我認爲這是與malloc免費鏈有關。 prefork實例的每個內存頁面可能都有一些空閒的內存空間。如果在隨機等級生成過程中分配了適合頁面中某個空閒區域的內容,那麼整個頁面將被複制到分叉過程中。
在windows中,您可以創建備用堆,並更改進程使用的默認堆。如果可能的話,它會消除這個問題。有什麼辦法可以在linux中做這樣的事情嗎?我的調查似乎表明你不能。
另一個可能的解決方案是,如果我可以以某種方式丟棄現有的malloc自由鏈,迫使malloc從操作系統分配新的內存用於後續調用。我試圖看看malloc的實現,看看這是否可能很容易,但它看起來可能有點複雜。如果有人對這個領域有什麼想法或者從這個方法開始的建議,我很樂意聽到它。
最後,如果有人有任何其他想法可能會出現這裏錯誤,我真的很想聽到他們。非常感謝!
因爲這是一個很大的現有代碼庫,所以我們不能完全繞過malloc/new,因爲這是一個很大的現有代碼庫,我們所有的資源加載器都非常高興地使用它們。我不想排除這種方法,但如果可能的話,我想繼續使用別人的內存分配器。 – Negs 2012-03-24 11:10:48
@Negs你可以使用自定義分配器,甚至劫持'malloc'。但是,請閱讀第二段。停止依靠牛,並做自己的'mmap'。 – cnicutar 2012-03-24 11:11:50
這仍然需要我編寫一個自定義分配器,雖然我可以訴諸這一點,但我想找到一個不需要我這樣做的解決方案。或許圍繞現有的malloc包裝方式來滿足我的需求? – Negs 2012-03-24 11:14:50