言歸正傳。我們在內存池(MemPool)技術詳解已經介紹了boost::pool組件。從內存管理觀念的變革來看,這是是一個傳統的MemPool組件,盡管也有一定的改進(但只是性能上的改進)。但boost::object_pool不同,它與我在C++內存管理變革強調的觀念非常吻合。可以認為,boost::object_pool是一種不通用的gc allocator組件。
我已經多次提出gc allocator的概念。這裡仍然需要強調一下,所謂gc allocator,是指具垃圾回收能力的allocator。C++內存管理變革(1) 中我們引入了這個概念,但是沒有明確gc allocator一詞。
boost: object_pool內存管理觀念
boost::object_pool的了不起之處在於,這是C++從庫的層次上頭一次承認,程序員在內存管理上是會犯錯誤的,由程序員來確保內存不洩漏是困難的。boost::object_pool允許你忘記釋放內存。我們來看一個例子:
class X { … };
void func()
{
boost::object_pool<X> alloc;
X* obj1 = alloc.construct();
X* obj2 = alloc.construct();
alloc.destroy(obj2);
}
如果boost::object_pool只是一個普通的allocator,那麼這段代碼顯然存在問題,因為obj1的析構函數沒有執行,申請的內存也沒有釋放。
但是這段代碼是完全正常的。是的,obj1的析構確實執行了,所申請內存也被釋放了。這就是說,boost::object_pool既支持你手工釋放內存(通過主動調用object_pool::destroy),也支持內存的自動回收(通過object_pool::~object_pool析構的執行)。這正符合gc allocator的規格。
注:內存管理更好的說法是對象管理。內存的申請和釋放更確切的說是對象的創建和銷毀。但是這裡我們不刻意區分這兩者的差異。
boost: object_pool與AutoFreeAlloc
我們知道,AutoFreeAlloc不支持手工釋放,而只能等到AutoFreeAlloc對象析構的時候一次性全部釋放內存。那麼,是否可以認為boost::object_pool是否比AutoFreeAlloc更加完備呢?
其實不然。boost::object_pool與AutoFreeAlloc都不是完整意義上的gc allocator。AutoFreeAlloc因為它只能一次性釋放,故此僅僅適用特定的用況。然而盡管AutoFreeAlloc不是普適的,但它是通用型的gc allocator。而boost::object_pool只能管理一種對象,並不是通用型的allocator,局限性其實更強。
boost: object_pool的實現細節
大家對boost::object_pool應該已經有了一個總體的把握。現在,讓我們深入到object_pool的實現細節中去。
在內存池(MemPool)技術詳解中,我們介紹boost::pool組件時,特意提醒大家留意pool::ordered_malloc/ordered_free函數。事實上,boost::object_pool的malloc/construct, free/destroy函數調用了pool::ordered_malloc, ordered_free函數,而不是pool::malloc, free函數。
讓我們解釋下為什麼。
其實這其中的關鍵,在於object_pool要支持手工釋放內存和自動回收內存(並自動執行析構函數)兩種模式。如果沒有自動析構,那麼普通的MemPool就足夠了,也就不需要ordered_free。既然有自動回收,同時又存在手工釋放,那麼就需要區分內存塊(MemBlock)中哪些結點(Node)是自由內存結點(FreeNode),哪些結點是已經使用的。對於哪些已經是自由內存的結點,顯然不能再調用對象的析構函數。
我們來看看object_pool::~object_pool函數的實現:
template <typename T, typename UserAllocator>
object_pool<T, UserAllocator>::~object_pool()
{
// handle trivial case
if (!this->list.valid())
return;
details::PODptr<size_type> iter = this->list;
details::PODptr<size_type> next = iter;
// Start ’freed_iter’ at beginning of free list
void * freed_iter = this->first;
const size_type partition_size = this->alloc_size();
do
{
// increment next
next = next.next();
// delete all contained objects that aren’t freed
// Iterate ’i' through all chunks in the memory block
for (char * i = iter.begin(); i != iter.end(); i += partition_size)
{
// If this chunk is free
if (i == freed_iter)
{
// Increment freed_iter to point to next in free list
freed_iter = nextof(freed_iter);
// Continue searching chunks in the memory block
continue;
}
// This chunk is not free (allocated), so call its destructor
static_cast<T *>(static_cast<void *>(i))->~T();
// and continue searching chunks in the memory block
}
// free storage
UserAllocator::free(iter.begin());
// increment iter
iter = next;
} while (iter.valid());
// Make the block list empty so that the inherited destructor doesn’t try to
// free it again.
this->list.invalidate();
}
這段代碼不難理解,object_pool遍歷所有申請的內存塊(MemBlock),並遍歷其中所有結點(Node),如果該結點不出現在自由內存結點(FreeNode)的列表(FreeNodeList)中,那麼,它就是用戶未主動釋放的結點,需要進行相應的析構操作。
現在你明白了,ordered_malloc是為了讓MemBlockList中的MemBlock有序,ordered_free是為了讓FreeNodeList中的所有FreeNode有序。而MemBlockList, FreeNodeList有序,是為了更快地檢測Node是自由的還是被使用的(這實際上是一個集合求交的流程,建議你看看std::set_intersection,它定義在STL的<algorithm>中)。