C++內存池(memory pool)管理

1.內存池

程序員在使用C++中的動態內存分配器時,new/delete, malloc/free等操作時,可能會出現以下問題:

  • Memory Leak:new一塊空間,但中間拋出錯誤,最後沒有釋放成功,導致memory leak;這個問題可以採用智能指針auto_ptr, shared_ptr, unique_ptr來解決
  • Mismatching Operators:new和delete沒有配對使用,如new數組時,沒有調用delete [] array,一個ptr被多次delete等錯誤操作
  • Fragmentation:當多次調用new和delete時,會讓heap上產生大量的外部碎片
  • Long execution time:new/delet操作或者庫函數malloc/free有可能需要系統調用,那麼操作的overhead就會比較大
new/delete的一個顯著特徵是:new會分配一塊內存空間,並調用構造函數對這塊空間進行初始化。delete會首先調用對象的析構函數,然後再釋放空間。

那麼如果我們一開始分配一塊大的空間buffer,然後從buffer中進行分配小的空間,並負責回收,這就是內存池的思想:
  • 預先申請好一塊內存區域,並把它分成定長的塊,當buffer中的內存不夠時:使用類似vector的擴張方法,每次內存不夠時,重新申請一塊長度爲已有內存兩倍的內存塊。
  • 每次需要內存申請時,將一塊尚未分配的塊返回。每次釋放時,將傳入的內存塊重新標記爲未分配。
定長內存池在工程中應用非常廣泛。代碼量少、效率高,非常適合用作大量同類型小數據的內存管理器。所謂定長內存池,就是buffer中的內存按固定長度進行分配和回收。

不同於定長內存池,不定長內存池可以在構造後申請各種不同大小的內存塊。

實現方法:內部維護多個定長內存池,每次找到最小的能滿足條件的內存池進行內存分配。如果申請的內存大於所有的內存池大小,則直接調用malloc()
如:分別維護1,2,4,8,16,32,64,128,256,512,1024bytes的定長內存池,對於每一個內存申請向上對齊到2的整次冪後分配對應大小的內存塊,此時空間最多浪費一倍,效率低於定長內存池

2. SGI STL中的分配器
默認使用兩級配置器
第一級配置器直接調用C的內存分配函數malloc()及realloc(),如果調用失敗則執行oom_malloc()
第二級配置器的做法是,如果區塊夠大,超過128bytes時,就移交第一級配置器處理。當區塊小於128bytes時,則以不定長內存池管理。
不定長內存池中維護16個定長內存池,大小分別爲8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128bytes,將所需的內存向上對齊至8的倍數後交由對應的定長內存池分配
所有stl容器默認使用上述stl::alloc進行內存管理



 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章