記憶體池 MemPool 技術詳解 經典記憶體池

2021-09-02 16:01:33 字數 3204 閱讀 1484

**

[url]

[align=center][b]概述[/b][/align]

記憶體池(mempool)技術備受推崇。我用google搜尋了下,沒有找到比較詳細的原理性的文章,故此補充乙個。另外,補充了boost::pool元件與經典mempool的差異。同時也描述了mempool在sgi-stl/stlport中的運用。

[align=center][b]經典的記憶體池技術[/b][/align]

經典的記憶體池(mempool)技術,是一種用於分配大量大小相同的小物件的技術。通過該技術可以極大加快記憶體分配/釋放過程。下面我們詳細解釋其中的奧妙。

經典的記憶體池只涉及兩個常量:memblocksize、itemsize(小物件的大小,但不能小於指標的大小,在32位平台也就是不能小於4位元組),以及兩個指標變數memblockheader、freenodeheader。開始,這兩個指標均為空。

class mempool

;struct _memblock ;

_memblock* m_pmemblockheader;

_freenode* m_pfreenodeheader;

public:

mempool(int nitemsize, int nmemblocksize = 2048)

: m_nitemsize(nitemsize), m_nmemblocksize(nmemblocksize),

m_pmemblockheader(null), m_pfreenodeheader(null)

};

其中指標變數memblockheader是把所有申請的記憶體塊(memblock)串成乙個鍊錶,以便通過它可以釋放所有申請的記憶體。freenodeheader變數則是把所有自由記憶體結點(freenode)串成乙個鏈。

這段話涉及兩個關鍵概念:[color=red]記憶體塊(memblock)[/color]和[color=red]自由記憶體結點(freenode)[/color]。記憶體塊大小一般固定為memblocksize位元組(除去用以建立鍊錶的指標外)。記憶體塊在申請之初就被劃分為多個記憶體結點(node)1,每個node大小為itemsize(小物件的大小),計memblocksize/itemsize個。這memblocksize/itemsize個記憶體結點剛開始全部是自由的,他們被串成鍊錶。我們看看申請/釋放記憶體過程,就很容易明白這樣做的目的。

[align=center][b]申請記憶體過程[/b][/align]

**如下:

void* mempool::malloc() // 沒有引數

void* pfreenode = m_pfreenodeheader;

m_pfreenodeheader = m_pfreenodeheader->pprev;

return pfreenode;

}

記憶體申請過程分為兩種情況:

在自由記憶體結點鍊錶(freenodelist)非空。在此情況下,alloc過程只是從鍊錶中摘下乙個結點的過程。

否則,意味著需要乙個新的記憶體塊(memblock)。這個過程需要將新申請的memblock切割成多個node,並把它們串起來,mempool技術的開銷主要在這。

[align=center][b]釋放記憶體過程[/b][/align]

**如下:

void mempool::free(void* p)

釋放過程極其簡單,只是把要釋放的結點掛到自由記憶體鍊錶(freenodelist)的開頭即可。

[align=center][b]效能分析[/b][/align]

mempool技術申請記憶體/釋放記憶體均極其快(比autofreealloc慢)。其記憶體分配過程多數情況下複雜度為o(1),主要開銷在freenodelist為空需要生成新的memblock時。記憶體釋放過程複雜度為o(1)。

[b]boost::pool[/b]

boost::pool是記憶體池技術的變種。主要的變化如下:

memblock改為非固定長度(memblocksize),而是:第1次申請時m_nitemsize*32,第2次申請時 m_nitemsize*64,第3次申請時m_nitemsize*128,以此類推。不採用固定的memblocksize,而採用這種做法**模型2,是乙個細節上的改良。

增加了ordered_free(void* p) 函式。ordered_free區別於free的是,free把要釋放的結點掛到自由記憶體鍊錶(freenodelist)的開頭, ordered_free則假設freenodelist是有序的,因此會遍歷freenodelist把要釋放的結點插入到合適的位置。我們已經看到,free的複雜度是o(1),非常快。但請注意ordered_free是比較費的操作,其複雜度是o(n)。這裡n是freenodelist的大小。對於乙個頻繁釋放/申請的系統,這個n很可能是個大數。這個boost描述得很清楚:

注意:不要認為boost提供ordered_free是多此一舉。後文我們會在討論boost::object_pool時解釋這一點。

[align=center][b]基於記憶體池技術的通用記憶體分配元件[/b][/align]

[size=medium][color=red]sgi stl把記憶體池(mempool)技術進行發揚光大,用它來實現其最根本的allocator。

其大體的思想是,建立16個mempool,<=8位元組的記憶體申請由0號mempool分配,<=16位元組的記憶體申請由1號 mempool分配,<=24位元組的記憶體有2號mempool分配,以此類推。最後,>128位元組的記憶體申請由普通的malloc分配。[/color][/size]

[align=center][b]記憶體池技術的缺陷[/b][/align]

遺憾的是,mempool技術可能導致記憶體占用只增不減。還沒有非常有效的辦法去避免這種情況的發生。不過我後來在scopealloc的實現中發現blockpool(是乙個簡化版的記憶體池)反倒避免了這一缺陷。

[align=center][b]注意[/b][/align]

以上**屬於偽**(struct _freenode、_memblock編譯通不過),並且去除了出錯處理。

[b]footnotes[/b]

1. boost:pool/object_pool 中稱之為塊(chunk)。

2. 是的,這是一種使用者記憶體需求的**模型,其實std::vector的記憶體增長亦採用了該模型。

記憶體池 MemPool 技術詳解

記憶體池 mempool 技術備受推崇。我用google搜尋了下,沒有找到比較詳細的原理性的文章,故此補充乙個。另外,補充了boost pool元件與經典mempool的差異。同時也描述了mempool在sgi stl stlport中的運用。經典的記憶體池 mempool 技術,是一種用於分配大量...

記憶體池 MemPool 技術詳解

記憶體池 mempool 技術備受推崇。我用google搜尋了下,沒有找到比較詳細的原理性的文章,故此補充乙個。另外,補充了boost pool元件與經典mempool的差異。同時也描述了mempool在sgi stl stlport中的運用。經典的記憶體池 mempool 技術,是一種用於分配大量...

記憶體池 MemPool 技術詳解

概述 記憶體池 mempool 技術備受推崇。我用google搜尋了下,沒有找到比較詳細的原理性的文章,故此補充乙個。另外,補充了boost pool元件與經典mempool的差異。同時也描述了mempool在sgi stl stlport中的運用。經典的記憶體池 mempool 技術,是一種用於分...