boost記憶體池的使用介紹
Boost庫的pool提供了一個記憶體池分配器,用於管理在一個獨立的、大的分配空間裡的動態記憶體分配。
Boost庫的pool主要適用於快速分配同樣大小的記憶體塊,尤其是反覆分配和釋放同樣大小的記憶體塊的情況。使用pool記憶體池主要有以下兩個優點:
1. 能夠有效地管理許多小型物件的分配和釋放工作,避免了自己去管理記憶體而產生的記憶體碎片和效率低下問題。
2. 告別程式記憶體洩漏的煩惱,pool庫會在內部對記憶體自動進行管理,避免了程式設計師一不小心而造成的記憶體洩漏問題。
pool庫主要提供了四種記憶體池介面,分別是
pool、object_pool、singleton_pool
1. pool
pool是最簡單也最容易使用的記憶體池類,可以返回一個簡單資料型別(POD) 的記憶體指標。它
pool很容易使用,可以像C中的malloc()一樣分配記憶體,然後隨意使用。除非有特殊要求,否則不必對分配的記憶體呼叫free()釋放,pool會很好地管理記憶體。例如:
#include <boost/pool/pool.hpp>
using namespace boost;
int main()
{
pool<> pl(sizeof(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_pool與pool的介面完全一致,可以分配簡單資料型別(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:標記而已,無意義;
RequestedSize:block的長度;
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相同。
4)pool_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_pool的tag是boost::fast_pool_allocator_tag。
總結:
boost::pool小巧高效,多多使用,
boost::singleton_pool多執行緒環境下使用,不要使用兩者的ordered_malloc/orderd_free函式。
boost::object_pool不建議使用,可以改造後使用。
pool_allocator/fast_pool_allocator推薦使用後者。用於與STL關連。。