乙個快速的記憶體分配池

2021-05-22 11:08:42 字數 1464 閱讀 1502

對於現代的遊戲引擎來說,為了提高效能和有效的管理記憶體,需要使用各種各樣的記憶體分配模型,記憶體池作為一種有效的分配模型被大量的使用,它通過一次分配足夠的記憶體來減少對new delelte使用以提高引擎的效能,並且由於每乙個記憶體塊都有相同的大小因此非常易於管理,並可以防止記憶體的洩露。它通常被用於需要分配大量相同物件的場合,如粒子系統這樣的地方。

對於在執行時可以明確知道分配數量的物體,可以通過乙個靜態陣列來實現它,但對於不知道分配數量的地方,設計就變的有些複雜,通常需要使用乙個鍊錶來進行實現,如stl的list容器,不過使用它有乙個很大的缺點,鍊錶對錶中的物件進行查詢操作時速度不是很理想,會極大影響它的效能。因此需要尋找乙個比較好的方法對其進行改進。

通常設計記憶體池有兩個問題必須考慮,乙個是記憶體分配的策略,由於你不是明確知道待分配物體的數量,因此每次分配多大數量的記憶體是乙個值得注意的問題。另乙個是如何對記憶體池進行管理,使用什麼樣的資料結構才能在常數時間內來獲得指定的記憶體。對於第乙個問題解決的方案很多,你可以每次都分配乙個指定數量的記憶體塊,也可以在每次分配時都分配比上一次多一倍的記憶體,哪種方案更好,需要你自己在實際使用中體會。第二個問題是本文的核心,一般的做法是將已經分配的記憶體塊分成兩個部分,已使用和未使用兩個鍊錶,但是這樣做的效能並不理想,下面看看如何對其進行改進:

我們先建立乙個結構用於儲存每次分配的一整塊記憶體:

sturct memchunk

在這個結構中m_ppre,m_pnext用於建立乙個雙向鍊錶將每一次分配的記憶體連線起來,m_nsize表示當前記憶體塊的大小,m_data是所分配的記憶體指標,必須注意這是乙個byte指標。我們現在假設當前的記憶體池用於對cobject物體分配記憶體,每次分配都一次分配64個cobject物體的記憶體,因此m_nsize的大小為64*sizeof(cobject)。下面看看如何儲存未使用的記憶體塊,我們需要乙個指標來指向當前未使用的記憶體塊。

void* s_pcurrent;

然後令它指向當前還未使用的記憶體塊。

s_pcurrent = pmemchunk->mdata;

下面是本文最關鍵的部分,為了提高效能我們令每乙個未使用的記憶體塊的頭部都儲存乙個指標,讓它指向下乙個未使用的記憶體塊,這樣就為未使用的記憶體塊形成了乙個單向鍊錶。當你需要乙個物體的記憶體時可以這麼做:

void* returnptr = s_pcurrent;

s_pcurrent = *((void **)s_pcurrent);

return returnptr;

這樣returnptr就是你要獲得的記憶體指標,而s_pcurrent通過乙個簡單的指標轉換巧妙的又指向了下乙個記憶體塊,如果上一句看不懂,請你重新複習一下c++教材中關於指標的解釋。

當你需要釋放乙個物體的記憶體時,方法和此類似。

*((void**)pmem = s_pcurrent;

s_pcurrent = pmem;

這樣就可以將記憶體塊重新連線到未使用的記憶體塊鍊錶中。通常對指標進行轉換的時間非常短,比一般的鍊錶的插入、刪除操作速度快的多,因此這個技巧是非常值得借鑑的做法。

乙個簡單的記憶體池

為什仫要使用記憶體池?1.通常我們用new delete和malloc free來管理記憶體,可能會需要頻繁的呼叫記憶體,減少執行時間,增加效率.2.避免記憶體碎片 傳統的new delete的弊端 1.分配記憶體時要檢視空閒分割槽表,根據一定的演算法來分配,比如最佳適應演算法,最差適應演算法.然後...

乙個簡單的記憶體池

記憶體池是我們經常使用的一種池,常見的池還有程序池 執行緒池和連線池,今天我們就先討論記憶體池。首先看一下池的定義 池 池就是在初始時,申請比剛開始要使用的資源大的多的資源空間,接下來使用時,直接從池中獲取資源。記憶體池 即在初始時申請分配一定數量的。大小相等的記憶體塊留作備用,此後如有需要直接從該...

乙個簡單記憶體池實現

最近面試被問了乙個記憶體池的實現,關鍵是記憶體塊的組織,說來慚愧,由於之前沒有詳細去了解過實現,只記得作業系統上有說過空閒鍊錶的實現,即按分配的塊用鍊錶鏈結,有小塊優先,大塊優先等 後來回來認真地找了幾個記憶體池實現的技術介紹,多數是以乙個固定塊,每個塊又有固定長度的單元組成。參考了網上的一些實現方...