作者:CppExplore 地址:http://www.shnenglu.com/CppExplore/
(2)boost::pool系列。boost的內存池最低層是simple_segregated_storage,類似于Loki中的chunk,在其中申請釋放block(boost中把block稱為chunk,暈死,這里還是稱其為block)采用了和loki的chunk中同樣的算法,不同的是simple_segregated_storage使用void*保存block的塊序號,loki中使用char,因此boost中的simple_segregated_storage沒有255的上限限制,自然也就不需要再其上再封裝一層類似與FixedAllocator的層面。另boost沒有屏蔽塊的大小,直接提供定長的接口給用戶,省掉了SmallObjAllocator層面。因此boost的內存池申請釋放block的時間復雜度都是O(1)(object_pool和pool_allocator除外),另避免的小內存的浪費,同時boost不能象loki那樣在將block歸還給內存池的時候根據chunk的空閑數量釋放內存歸還給系統,只能顯式調用釋放內存函數或者等內存池銷毀的時候,基本上和內存池生命周期內永不釋放沒什么區(qū)別。
boost的最低層是simple_segregated_storage,主要算法和loki中的chunk一樣,不多說了。這里說下影響上層接口的兩類實現:add_block/malloc/free、add_ordered_block/malloc/ordered_free,兩種低層實現造成boost上層設計的成功與失敗,前者效率高,和loki一樣直接增加釋放,時間復雜度O(1),后者掃描排序,時間復雜度O(n)。
boost提供了四種內存池模型供使用:pool、object_pool、singleton_pool、pool_allocator/fast_pool_allocator。
1)pool
基本的定長內存池
#include <boost/pool/pool.hpp>
typedef struct student_st


{
char name[10];
int age;
}CStudent;
int main()


{
boost::pool<> student_pool(sizeof(CStudent));
CStudent * const obj=(CStudent *)student_pool.malloc();
student_pool.free(obj);
return 0;
}
pool的模版參數只有一個分配子類型,boost提供了兩種default_user_allocator_new_delete/default_user_allocator_malloc_free,指明申請釋放內存的時候使用new/delete,還是malloc/free,默認是default_user_allocator_new_delete。構造函數有2個參數:nrequested_size,nnext_size。nrequested_size是block的大?。ㄒ驗関oid*保存序號,因此boost內置了block的最小值,nrequested_size過小則取內置值),nnext_size是simple_segregated_storage中內存不足的時候,申請的block數量,默認是32。最全面的實例化pool類似這樣:boost::pool<boost::default_user_allocator_malloc_free> student_pool(sizeof(CStudent),255);
pool提供的函數主要有:
malloc/free |
基于add_block/malloc/free實現,高效
|
ordered_malloc/ordered_free |
基于add_ordered_block/malloc/ordered_free實現,在pool中無任何意義,切勿使用。
|
release_memory/purge_memory |
前者釋放池中未使用內存,后者釋放池中所有內存。另池析構也會釋放內存
|
2)object_pool對象內存池,這是最失敗的一個內存池設計。
#include <boost/pool/object_pool.hpp>


class A
{
public:

A():data_(0)
{}
private:
int data_;
};
int main()


{
boost::object_pool<A> obj_pool;
A *const pA=obj_pool.construct();
obj_pool.destroy(pA);
return 0;
}

object_pool繼承至pool,有兩個模版參數,第一個就是對象類型,第二個是分配子類型,默認同pool是default_user_allocator_new_delete。構造函數參數只有nnext_size,意義以及默認值同pool。最全面的實例化object_pool類似這樣:boost::pool<A,boost::default_user_allocator_malloc_free> obj_pool(255);
object_pool提供的函數主要有(繼承至父類的略):
malloc/free |
復寫pool的malloc/free,add_ordered_block/malloc/ordered_free實現 |
construct/destroy |
基于本類的malloc/free實現,額外調用默認構造函數和默認析構函數。 |
~object_pool |
單獨拿出這個說下,若析構的時候有對象未被destroy,可以檢測到,釋放內存前對其執(zhí)行destroy |
為什么boost::object_pool要設計成這樣?能調用構造函數和析構函數顯然不是boost::object_pool類設計的出發(fā)點,因為構造函數只能執(zhí)行默認構造函數(
首次發(fā)表錯誤:可以調用任意的構造函數,參見代碼文件:boost/pool/detail/pool_construct.inc和boost/pool/detail/pool_construct_simple.inc,感謝eXile指正),近似于無,它的重點是內存釋放時候的清理工作,這個工作默認的析構函數就足夠了。apr_pool內存池中就可以注冊內存清理函數,在釋放內存的時刻執(zhí)行關閉文件描述符、關閉socket等操作。boost::object_pool也想實現同樣的功能,因此設計了destroy這個函數,而同時為了防止用戶遺漏掉這個調用,而又在內存池析構的時候進行了檢測回收。為了這個目的而又不至于析構object_pool的時間復雜度是O(n平方),boost::object_pool付出了沉重的代價,在每次的destoy都執(zhí)行排序功能,時間復雜度O(n),最后析構的時間復雜度是O(n),同樣為了這個目的,從simple_segregated_storage增加了add_ordered_block/ordered_free,pool增加了ordered_malloc/ordered_free等累贅多余的功能。
基于上面討論的原因,boost::object_pool被設計成了現在的樣子,成了一個雞肋類。類的設計者似乎忘記了內存池使用的初衷,忘記了內存池中內存申請釋放的頻率很高,遠遠大于內存池對象的析構。如果你依然想使用類似于此的內存清理功能,可以在boost::object_pool上修改,不復寫malloc/free即可,重寫object_pool的析構,簡單釋放內存就好,因此析構object_pool前不要忘記調用destroy,這也是使用placement new默認遵守的規(guī)則,或者保持以前的析構函數,犧牲析構時的性能。placement new的作用是為已經申請好的內存調用構造函數,使用流程為(1)申請內存buf(2)調用placement new:new(buf)construtor()(3)調用析構destructor()(4)釋放內存buf。#include<new>可以使用placement new。
3)singleton_poolpool的加鎖版本。
#include <boost/pool/singleton_pool.hpp>
typedef struct student_st


{
char name[10];
int age;
}CStudent;

typedef struct singleton_pool_tag
{}singleton_pool_tag;
int main()


{
typedef boost::singleton_pool<singleton_pool_tag,sizeof(CStudent)> global;
CStudent * const df=(CStudent *)global::malloc();
global::free(df);
return 0;
}
singleton_pool為單例類,是對pool的加鎖封裝,適用于多線程環(huán)境,其中所有函數都是靜態(tài)類型。它的模版參數有5個,tag:標記而已,無意義;RequestedSize:block的長度;UserAllocator:分配子,默認還是default_user_allocator_new_delete;Mutex:鎖機制,默認值最終依賴于系統環(huán)境,linux下是pthread_mutex,它是對pthread_mutex_t的封裝;NextSize:內存不足的時候,申請的block數量,默認是32。最全面的使用singleton_pool類似這樣:typedef boost::singleton_pool<singleton_pool_tag,sizeof(CStudent),default_user_allocator_new_delete,details::pool::default_mutex,200> global;
它暴露的函數和pool相同。
4)pool_allocator/fast_pool_allocator
stl::allocator的替換方案。兩者都是基于singleton_pool實現,實現了stl::allocator要求的接口規(guī)范。兩者的使用相同,區(qū)別在于pool_allocator的實現調用ordered_malloc/ordered_free,fast_pool_allocator的實現調用malloc/free,因此推薦使用后者。
#include <boost/pool/pool_alloc.hpp>
#include <vector>
typedef struct student_st


{
char name[10];
int age;
}CStudent;

int main()


{
std::vector<CStudent *,boost::fast_pool_allocator<CStudent *> > v(8);
CStudent *pObj=new CStudent();
v[1]=pObj;
boost::singleton_pool<boost::fast_pool_allocator_tag,sizeof(CStudent *)>::purge_memory();
return 0;
}

fast_pool_allocator的模版參數有四個:類型,分配子,鎖類型,內存不足時的申請的block數量,后三者都有默認值,不再說了。它使用的singleton_pool的tag是boost::fast_pool_allocator_tag。
評價:boost::pool小巧高效,多多使用,多線程環(huán)境下使用boost::singleton_pool,不要使用兩者的ordered_malloc/ordered_free函數。boost::object_pool不建議使用,可以改造后使用。pool_allocator/fast_pool_allocator推薦使用后者。
未完 待續(xù).................... 不過這個主題暫時不寫了 等有時間了