A fixed-size, multi-thread optimized allocator
原文URL:http://list.cs.brown.edu/people/jwicks/libstdc++/html/ext/mt_allocator.html 簡介
mt allocator是一個固定大小(2的冪)記憶體的分配器,最初是為多線程應用程式(以下簡稱為MT程式)設計的。經過多年的改進,現在它在單線程應用程式(以下簡稱為ST程式)裡也有出色的表現了。
本文的目的是從應用程式的角度描述mt allocator的“內幕”。 總體設計
mt allocator有3個組成部分:描述記憶體池特徵的參數,把記憶體池關聯到通用或專用方案的policy類,和從policy類繼承來的實際的記憶體 Clerk類。
描述記憶體池特徵的參數是:
template<bool _Thread>
class __pool
這個類表示是否支援線程,然後對多線程(bool==true)和單線程(bool==false)情況進行顯式特化。可以用定製的參數來替代這個類。
對於policy類,至少有2種不同的風格,每種都可以和上面不同的記憶體池參數單獨搭配:第一個策略,__common_pool_policy,實現了一個通用記憶體池,即使分配的物件類型不同,比如char和long,也使用同一個的記憶體池。這是預設的策略。 template < bool _Thread >
struct __common_pool_policy
template < typename _Tp, bool _Thread >
struct __per_type_pool_policy
第二個策略,__per_type_pool_policy,對每個物件類型都實現了一個單獨的記憶體池,於是char和long會使用不同的記憶體池。這樣可以對某些類型進行單獨調整。
把上面這些放到一起,我們就得到了實際的記憶體 Clerk: template < typename _Tp, typename _Poolp = __default_policy >
class __mt_alloc : public __mt_alloc_base < _Tp > , _Poolp
這個類有標準庫要求的介面,比如allocate和deallocate函數等。 可調參數
有些配置參數可以修改,或調整。有一個嵌套類:包含了所有可調的參數,即: struct __pool_base::_Tune
l 位元組對齊
l 多少位元組以上的記憶體直接用new分配
l 可分配的最小的記憶體塊大小
l 每次從OS申請的記憶體塊的大小
l 可支援的最多線程數目
l 單個線程能儲存的空閑塊的百分比(超過的空閑塊會歸還給全域空閑鏈表)
l 是否直接使用new和delete
對這些參數的調整必須在任何記憶體配置動作之前,即記憶體 Clerk初始化的時候,比如:
#include < ext / mt_allocator.h >
struct pod
{
int i;
int j;
} ;
int main()
{
typedef pod value_type;
typedef __gnu_cxx::__mt_alloc<value_type> allocator_type;
typedef __gnu_cxx::__pool_base::_Tune tune_type;
tune_type t_default;
tune_type t_opt(16, 5120, 32, 5120, 20, 10, false);
tune_type t_single(16, 5120, 32, 5120, 1, 10, false);
tune_type t;
t = allocator_type::_M_get_options();
allocator_type::_M_set_options(t_opt);
t = allocator_type::_M_get_options();
allocator_type a;
allocator_type::pointer p1 = a.allocate(128);
allocator_type::pointer p2 = a.allocate(5128);
a.deallocate(p1, 128);
a.deallocate(p2, 5128);
return 0;
}
初始化
靜態變數(記憶體鏈表的指標,控制參數等)的初始化為預設的值,比如: template < typename _Tp > size_t
__mt_alloc < _Tp > ::_S_freelist_headroom = 10 ;
首次調用allocate()時,也會調用_S_init()函數。為了保證在MT程式裡它只被調用一次,我們使用了__gthread_once(參數是_S_once_mt和_S_init)函數;在ST程式裡則檢查靜態bool變數_S_initialized。
_S_init()函數:如果設定了GLIBCXX_FORCE_NEW環境變數,它會把_S_force_new設定成true,這樣allocate()就直接用new來申請記憶體,deallocate()用delete來釋放記憶體。
如果沒有設定GLIBCXX_FORCE_NEW,ST和MT程式都會:
1)計算bin的個數。bin是指2的指數位元組的記憶體集合。預設情況下,mt allocator只處理128位元組以內的小記憶體配置(或者通過在