作者:CppExplore 地址:
http://www.cppblog.com/CppExplore/(2)boost::pool系列。boost的內(nèi)存池最低層是simple_segregated_storage,類(lèi)似于Loki中的chunk,在其中申請(qǐng)釋放block(boost中把block稱(chēng)為chunk,暈死,這里還是稱(chēng)其為block)采用了和loki的chunk中同樣的算法,不同的是simple_segregated_storage使用void*保存block的塊序號(hào),loki中使用char,因此boost中的simple_segregated_storage沒(méi)有255的上限限制,自然也就不需要再其上再封裝一層類(lèi)似與FixedAllocator的層面。另boost沒(méi)有屏蔽塊的大小,直接提供定長(zhǎng)的接口給用戶(hù),省掉了SmallObjAllocator層面。因此boost的內(nèi)存池申請(qǐng)釋放block的時(shí)間復(fù)雜度都是O(1)(object_pool和pool_allocator除外),另避免的小內(nèi)存的浪費(fèi),同時(shí)boost不能象loki那樣在將block歸還給內(nèi)存池的時(shí)候根據(jù)chunk的空閑數(shù)量釋放內(nèi)存歸還給系統(tǒng),只能顯式調(diào)用釋放內(nèi)存函數(shù)或者等內(nèi)存池銷(xiāo)毀的時(shí)候,基本上和內(nèi)存池生命周期內(nèi)永不釋放沒(méi)什么區(qū)別。
boost的最低層是simple_segregated_storage,主要算法和loki中的chunk一樣,不多說(shuō)了。這里說(shuō)下影響上層接口的兩類(lèi)實(shí)現(xiàn):add_block/malloc/free、add_ordered_block/malloc/ordered_free,兩種低層實(shí)現(xiàn)造成boost上層設(shè)計(jì)的成功與失敗,前者效率高,和loki一樣直接增加釋放,時(shí)間復(fù)雜度O(1),后者掃描排序,時(shí)間復(fù)雜度O(n)。
boost提供了四種內(nèi)存池模型供使用:pool、object_pool、singleton_pool、pool_allocator/fast_pool_allocator。
1)pool
基本的定長(zhǎng)內(nèi)存池
#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的模版參數(shù)只有一個(gè)分配子類(lèi)型,boost提供了兩種default_user_allocator_new_delete/default_user_allocator_malloc_free,指明申請(qǐng)釋放內(nèi)存的時(shí)候使用new/delete,還是malloc/free,默認(rèn)是default_user_allocator_new_delete。構(gòu)造函數(shù)有2個(gè)參數(shù):nrequested_size,nnext_size。nrequested_size是block的大小(因?yàn)関oid*保存序號(hào),因此boost內(nèi)置了block的最小值,nrequested_size過(guò)小則取內(nèi)置值),nnext_size是simple_segregated_storage中內(nèi)存不足的時(shí)候,申請(qǐng)的block數(shù)量,默認(rèn)是32。最全面的實(shí)例化pool類(lèi)似這樣:boost::pool<boost::default_user_allocator_malloc_free> student_pool(sizeof(CStudent),255);
pool提供的函數(shù)主要有:
malloc/free 基于add_block/malloc/free實(shí)現(xiàn),高效
ordered_malloc/ordered_free 基于add_ordered_block/malloc/ordered_free實(shí)現(xiàn),在pool中無(wú)任何意義,切勿使用。
release_memory/purge_memory 前者釋放池中未使用內(nèi)存,后者釋放池中所有內(nèi)存。另池析構(gòu)也會(huì)釋放內(nèi)存
2)object_pool
對(duì)象內(nèi)存池,這是最失敗的一個(gè)內(nèi)存池設(shè)計(jì)。
#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,有兩個(gè)模版參數(shù),第一個(gè)就是對(duì)象類(lèi)型,第二個(gè)是分配子類(lèi)型,默認(rèn)同pool是default_user_allocator_new_delete。構(gòu)造函數(shù)參數(shù)只有nnext_size,意義以及默認(rèn)值同pool。最全面的實(shí)例化object_pool類(lèi)似這樣:boost::pool<A,boost::default_user_allocator_malloc_free> obj_pool(255);
object_pool提供的函數(shù)主要有(繼承至父類(lèi)的略): malloc/free 復(fù)寫(xiě)pool的malloc/free,add_ordered_block/malloc/ordered_free實(shí)現(xiàn)
construct/destroy 基于本類(lèi)的malloc/free實(shí)現(xiàn),額外調(diào)用默認(rèn)構(gòu)造函數(shù)和默認(rèn)析構(gòu)函數(shù)。
~object_pool 單獨(dú)拿出這個(gè)說(shuō)下,若析構(gòu)的時(shí)候有對(duì)象未被destroy,可以檢測(cè)到,釋放內(nèi)存前對(duì)其執(zhí)行destroy
為什么boost::object_pool要設(shè)計(jì)成這樣?能調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)顯然不是boost::object_pool類(lèi)設(shè)計(jì)的出發(fā)點(diǎn),因?yàn)闃?gòu)造函數(shù)只能執(zhí)行默認(rèn)構(gòu)造函數(shù)(首次發(fā)表錯(cuò)誤:可以調(diào)用任意的構(gòu)造函數(shù),參見(jiàn)代碼文件:boost/pool/detail/pool_construct.inc和boost/pool/detail/pool_construct_simple.inc,感謝eXile指正),近似于無(wú),它的重點(diǎn)是內(nèi)存釋放時(shí)候的清理工作,這個(gè)工作默認(rèn)的析構(gòu)函數(shù)就足夠了。apr_pool內(nèi)存池中就可以注冊(cè)內(nèi)存清理函數(shù),在釋放內(nèi)存的時(shí)刻執(zhí)行關(guān)閉文件描述符、關(guān)閉socket等操作。boost::object_pool也想實(shí)現(xiàn)同樣的功能,因此設(shè)計(jì)了destroy這個(gè)函數(shù),而同時(shí)為了防止用戶(hù)遺漏掉這個(gè)調(diào)用,而又在內(nèi)存池析構(gòu)的時(shí)候進(jìn)行了檢測(cè)回收。為了這個(gè)目的而又不至于析構(gòu)object_pool的時(shí)間復(fù)雜度是O(n平方),boost::object_pool付出了沉重的代價(jià),在每次的destoy都執(zhí)行排序功能,時(shí)間復(fù)雜度O(n),最后析構(gòu)的時(shí)間復(fù)雜度是O(n),同樣為了這個(gè)目的,從simple_segregated_storage增加了add_ordered_block/ordered_free,pool增加了ordered_malloc/ordered_free等累贅多余的功能。
基于上面討論的原因,boost::object_pool被設(shè)計(jì)成了現(xiàn)在的樣子,成了一個(gè)雞肋類(lèi)。類(lèi)的設(shè)計(jì)者似乎忘記了內(nèi)存池使用的初衷,忘記了內(nèi)存池中內(nèi)存申請(qǐng)釋放的頻率很高,遠(yuǎn)遠(yuǎn)大于內(nèi)存池對(duì)象的析構(gòu)。如果你依然想使用類(lèi)似于此的內(nèi)存清理功能,可以在boost::object_pool上修改,不復(fù)寫(xiě)malloc/free即可,重寫(xiě)object_pool的析構(gòu),簡(jiǎn)單釋放內(nèi)存就好,因此析構(gòu)object_pool前不要忘記調(diào)用destroy,這也是使用placement new默認(rèn)遵守的規(guī)則,或者保持以前的析構(gòu)函數(shù),犧牲析構(gòu)時(shí)的性能。placement new的作用是為已經(jīng)申請(qǐng)好的內(nèi)存調(diào)用構(gòu)造函數(shù),使用流程為(1)申請(qǐng)內(nèi)存buf(2)調(diào)用placement new:new(buf)construtor()(3)調(diào)用析構(gòu)destructor()(4)釋放內(nèi)存buf。#include<new>可以使用placement new。
3)singleton_pool
pool的加鎖版本。
#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為單例類(lèi),是對(duì)pool的加鎖封裝,適用于多線程環(huán)境,其中所有函數(shù)都是靜態(tài)類(lèi)型。它的模版參數(shù)有5個(gè),tag:標(biāo)記而已,無(wú)意義;RequestedSize:block的長(zhǎng)度;UserAllocator:分配子,默認(rèn)還是default_user_allocator_new_delete;Mutex:鎖機(jī)制,默認(rèn)值最終依賴(lài)于系統(tǒng)環(huán)境,linux下是pthread_mutex,它是對(duì)pthread_mutex_t的封裝;NextSize:內(nèi)存不足的時(shí)候,申請(qǐng)的block數(shù)量,默認(rèn)是32。最全面的使用singleton_pool類(lèi)似這樣:typedef boost::singleton_pool<singleton_pool_tag,sizeof(CStudent),default_user_allocator_new_delete,details::pool::default_mutex,200> global;
它暴露的函數(shù)和pool相同。
4)pool_allocator/fast_pool_allocator
stl::allocator的替換方案。兩者都是基于singleton_pool實(shí)現(xiàn),實(shí)現(xiàn)了stl::allocator要求的接口規(guī)范。兩者的使用相同,區(qū)別在于pool_allocator的實(shí)現(xiàn)調(diào)用ordered_malloc/ordered_free,fast_pool_allocator的實(shí)現(xiàn)調(diào)用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的模版參數(shù)有四個(gè):類(lèi)型,分配子,鎖類(lèi)型,內(nèi)存不足時(shí)的申請(qǐng)的block數(shù)量,后三者都有默認(rèn)值,不再說(shuō)了。它使用的singleton_pool的tag是boost::fast_pool_allocator_tag。
評(píng)價(jià):boost::pool小巧高效,多多使用,多線程環(huán)境下使用boost::singleton_pool,不要使用兩者的ordered_malloc/ordered_free函數(shù)。boost::object_pool不建議使用,可以改造后使用。pool_allocator/fast_pool_allocator推薦使用后者。
未完 待續(xù).................... 不過(guò)這個(gè)主題暫時(shí)不寫(xiě)了 等有時(shí)間了
posted on 2008-02-20 15:09
cppexplore 閱讀(1943)
評(píng)論(14) 編輯 收藏引用