SGI STL的記憶體池

2021-06-01 05:32:59 字數 1471 閱讀 6824

tl中各種容器都有乙個可選的模板引數:allocator,也就是乙個負責記憶體分配的元件。stl標準規定的allcator

被定義在memory檔案中。stl標準規定的allocator只是單純地封裝operator new,效率上有點過意不去。

sgi實現的stl裡,所有的容器都使用sgi自己定義的allocator。這個allocator實現了乙個small object的記憶體池。

loki裡為了處理小物件的記憶體分配,也實現了類似的記憶體管理機制。

該記憶體池大致上,就是一大塊一大塊地從系統獲取記憶體,然後將其分成很多小塊以鍊錶的形式鏈結起來。其內部

有很多不同型別的鍊錶,不同的鍊錶維護不同大小的記憶體塊。每一次客戶端要求分配記憶體時,allcator就根據請求

的大小找到相應的鍊錶(最接近的尺寸),然後從煉表裡取出記憶體。當客戶端歸還記憶體時,allocator就將這塊記憶體

放回到對應的煉表裡。

我簡單地畫了幅圖表示整個結構:

allocator內部維護乙個鍊錶陣列,陣列元素全部是煉表頭指標。鍊錶a每乙個節點維護乙個8bytes的記憶體塊,鍊錶

b每乙個節點維護乙個16bytes的記憶體塊。

當客戶端請求分配10bytes的記憶體時,allocator將10調整為最接近的16bytes(只能大於10bytes),然後發現16bytes

這個鍊錶(鍊錶b)裡有可用記憶體塊,於是從b裡取出一塊記憶體返回。當客戶端歸還時,allocator找到對應的鍊錶,將

記憶體重新放回鍊錶b即可。

大致過程就這麼簡單,也許有人要說用鍊錶維護一塊記憶體,鍊錶本身就會浪費一些記憶體(在我很早前接觸記憶體池時,

總會看到類似的論點= =|),其實通過一些簡單的技巧是完全可以避免的。例如,這裡allocator維護了很多記憶體塊,

反正這些記憶體本身就是閒置的,因此我們就可以直接在這些記憶體裡記錄鍊錶的資訊(下乙個元素)。

還是寫點**詳細說下這個小技巧:

obj; 

void

*mem 

=malloc( 

100);

obj 

*header 

=(obj

*) mem;

obj 

*cur_obj 

=header;

obj 

*next_obj 

=cur_obj;

for( 

inti =0

; ; 

++i )

else

free( mem );

這樣,通過header指標和next域,就可以逐塊(這裡是10byts)地訪問mem所指向的記憶體,而這些鍊錶的節點,都

是直接儲存在這塊記憶體裡的,所以完全沒有額外消耗。

我用c模仿著sgi的這個allocator寫了個可配置的記憶體池,在其上按照stl的標準包裝了乙個allocator,可以直接

用於vc自帶的stl裡。

測試**

稍微測試了下,發現在不同的機器上有明顯的差距。

SGI STL空間配置器和記憶體池

最近在看侯捷老師的 stl原始碼剖析 非常感嘆其中空間配置器實現的巧妙和細緻,對效率真正是錙銖必較。一般我們所習慣的記憶體配置和釋放是通過new和delete來完成的,而new運算包含了兩個階段 1.呼叫 operator new配置記憶體 2.呼叫建構函式 foo 構造物件。delete運算也包含...

SGI STL記憶體分配管理

大多數時候,分配記憶體一般是採用malloc或new,stl記憶體分配是怎麼樣的呢?stl的記憶體採用的是 兩級記憶體配置方案。流程如下 第一級記憶體方案,就是malloc 為什麼不用new?歷史原因 c 不提供realloc方法,詳見這裡就不在贅述了,下面重點講下第二級記憶體池方案。實際上,第二級...

記憶體池 C 記憶體池

c c 下記憶體管理是讓幾乎每乙個程式設計師頭疼的問題,分配足夠的記憶體 追蹤記憶體的分配 在不需要的時候釋放記憶體 這個任務相當複雜。1.呼叫malloc new,系統需要根據 最先匹配 最優匹配 或其他演算法在記憶體空閒塊表中查詢一塊空閒記憶體,呼叫free delete,系統可能需要合併空閒記...