1. 程式人生 > >boost記憶體池的使用介紹

boost記憶體池的使用介紹

Boost庫的pool提供了一個記憶體池分配器,用於管理在一個獨立的、大的分配空間裡的動態記憶體分配。

Boost庫的pool主要適用於快速分配同樣大小的記憶體塊,尤其是反覆分配和釋放同樣大小的記憶體塊的情況。使用pool記憶體池主要有以下兩個優點:

1. 能夠有效地管理許多小型物件的分配和釋放工作,避免了自己去管理記憶體而產生的記憶體碎片和效率低下問題。

2.  告別程式記憶體洩漏的煩惱,pool庫會在內部對記憶體自動進行管理,避免了程式設計師一不小心而造成的記憶體洩漏問題。

pool庫主要提供了四種記憶體池介面,分別是

poolobject_poolsingleton_pool

pool_allocator/fast_pool_allocator

1.   pool

pool是最簡單也最容易使用的記憶體池類,可以返回一個簡單資料型別(POD) 的記憶體指標。它

pool很容易使用,可以像C中的malloc()一樣分配記憶體,然後隨意使用。除非有特殊要求,否則不必對分配的記憶體呼叫free()釋放,pool會很好地管理記憶體。例如:

#include <boost/pool/pool.hpp>     

using namespace boost;    

int main()    

{        

    pool<> pl(sizeof(int

));             //一個可分配int的記憶體池

    int *p = (int *)pl.malloc();        //必須把void*轉換成需要的型別

    assert(pl.is_from(p));         

    pl.free(p);                         //釋放記憶體池分配的記憶體塊

    for (int i = 0;i < 100; ++i)        //連續分配大量的記憶體

    {     

        pl.ordered_malloc(10);    

    }    

}   

2.  object_pool

object_pool用於類例項(物件)的記憶體池,它的功能與pool類似,但會在析構時對所有已經分配的記憶體塊呼叫解構函式,從而正確地釋放資源。

malloc()free()函式分別分配和釋放一塊型別為ElementType*的記憶體塊,同樣,可以用is_from()來測試記憶體塊的歸屬,只有是本記憶體池分配的記憶體才能被free()釋放。但它們被呼叫時並不呼叫類的建構函式和解構函式,也就是說操作的是一塊原始記憶體塊,裡面的值是未定義的,因此我們應當儘量少使用malloc()free()

object_pool的特殊之處是construct()destroy()函式,這兩個函式是object_ pool的真正價值所在。construct()實際上是一組函式,有多個引數的過載形式(目前最多支援3個引數,但可以擴充套件),它先呼叫malloc()分配記憶體,然後再在記憶體塊上使用傳入的引數呼叫類的建構函式,返回的是一個已經初始化的物件指標。destory()則先呼叫物件的解構函式,然後再用free()釋放記憶體塊。

這些函式都不會丟擲異常,如果記憶體分配失敗,將返回0

object_pool的用法也是很簡單,我們既可以像pool那樣分配原始記憶體塊,也可以使用construct()來直接在記憶體池中建立物件。當然,後一種使用方法是最方便的,也是本書所推薦的。

下面的程式碼示範了object_pool的用法:

#include <boost/pool/object_pool.hpp>    

using namespace boost;    

struct demo_class                           //一個示範用的類

{    

public:        

    int a,b,c;        

    demo_class(int x = 1, int y = 2, int z = 3):a(x),b(y),c(z){}    

};    

int main()    

{        

    object_pool<demo_class> pl;             //物件記憶體池

    demo_class *p = pl.malloc();            //分配一個原始記憶體塊

    assert(pl.is_from(p));       //p指向的記憶體未經過初始化

    assert(p->a!=1 || p->b != 2 || p->c !=3);         

    p = pl.construct(7, 8, 9);              //構造一個物件,可以傳遞引數

    assert(p->a == 7);         

    object_pool<string> pls;                //定義一個分配string物件的記憶體池

    for (int i = 0; i < 10 ; ++i)           //連續分配大量string物件

    {            

        string *ps = pls.construct("hello object_pool");            

        cout << *ps << endl;        

    }    

}                                           //所有建立的物件在這裡都被正確析構、釋放記憶體

3.   singleton_pool

singleton_poolpool的介面完全一致,可以分配簡單資料型別(POD)的記憶體指標,但它是一個單件,並提供執行緒安全。

singleton_pool主要有兩個模板型別引數(其餘的可以使用預設值)。第一個Tag僅僅是用於標記不同的單件,可以是空類,甚至是宣告。第二個引數RequestedSize等同於pool建構函式中的整數requested_ size,指示pool分配記憶體塊的大小。

singleton_pool的介面與pool完全一致,但成員函式均是靜態的,因此不需要宣告singleton_pool的例項 ,直接用域操作符::來呼叫靜態成員函式。因為singleton_pool是單件,所以它的生命週期與整個程式同樣長,除非手動呼叫release_memory()purge_memory(),否則singleton_pool不會自動釋放所佔用的記憶體。除了這兩點,singleton_pool的用法與pool完全相同。

下面的程式碼示範了singleton_pool的用法:

#include <boost/pool/singleton_pool.hpp>     

using namespace boost;    

struct pool_tag{};                                  //僅僅用於標記的空類  

typedef singleton_pool<pool_tag, sizeof(int)> spl;  //記憶體池定義  

int main()    

{        

    int *p = (int *)spl::malloc();                      //分配一個整數記憶體塊  

    assert(spl::is_from(p));        

    spl::release_memory();                              //釋放所有未被分配的記憶體  

}                                                       //spl的記憶體直到程式結束才完  

singleton_pool在使用時最好使用typedef來簡化名稱,否則會使得型別名過於冗長而難以使用。如程式碼中所示:

typedef singleton_pool<pool_tag, sizeof(int)> spl;   

用於標記的類pool_tag可以再進行簡化,直接在模板引數列表中宣告tag類,這樣可以在一條語句中完成對singleton_pool的型別定義,例如:

typedef singleton_pool<struct pool_tag, sizeof(int)> spl;   

singleton_pool為單例類,是對pool的加鎖封裝,適用於多執行緒環境,其中所有函式都是靜態型別。它的模版引數有5個,

tag標記而已,無意義;

RequestedSizeblock的長度;

UserAllocator分配子,預設還是default_user_allocator_new_delete

Mutex鎖機制,預設值最終依賴於系統環境,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相同。

4pool_allocator/fast_pool_allocator

    stl::allocator的替換方案兩者都是基於singleton_pool實現,實現了stl::allocator要求的介面規範。兩者的使用相同,區別在於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_pooltagboost::fast_pool_allocator_tag

總結:

boost::pool小巧高效,多多使用

boost::singleton_pool多執行緒環境下使用,不要使用兩者的ordered_malloc/orderd_free函式。

boost::object_pool不建議使用,可以改造後使用。

pool_allocator/fast_pool_allocator推薦使用後者。用於與STL關連。。