Source
#ifndef __KIMI_BOOST_POOL
#define __KIMI_BOOST_POOL
#pragma once
// std::less, std::less_equal, std::greater
#include <functional>
// new[], delete[], std::nothrow
#include <new>
// std::size_t, std::ptrdiff_t
#include <cstddef>
// std::malloc, std::free
#include <cstdlib>
// std::invalid_argument
#include <exception>
// std::max
#include <algorithm>
#include <boost/pool/detail/ct_gcd_lcm.hpp>
#include <boost/pool/detail/gcd_lcm.hpp>
#include <boost/static_assert.hpp>
namespace kimi_boost
{
///声明/
//底层分配策略的两个策略类(policy classes)
struct default_user_allocator_new_delete;
struct default_user_allocator_malloc_free;
//管理Block的类(每个Block分为多个Chunk)
template <typename SizeType = std::size_t>
class simple_segregated_storage;
//内存池(继承自'class simple_segregated_storage')
template <typename UserAllocator = default_user_allocator_new_delete>
class pool;
//对象池(继承自'内存池'),增加了对象的自动构造,析构
template <typename T, typename UserAllocator = default_user_allocator_new_delete>
class object_pool;
namespace details
{
//POD代表向系统索要的一大块Block,再加上必要的管理
//PODptr管理一个个Block,形成一个free list
template <typename SizeType>
class PODptr;
};
}//namespace kimi_boost
///实现/
namespace kimi_boost
{
//new/delete的分配策略
struct default_user_allocator_new_delete
{
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
static char * malloc(const size_type bytes)
{ return new (std::nothrow) char[bytes]; }
static void free(char * const block)
{ delete [] block; }
};
//malloc/free的分配策略
struct default_user_allocator_malloc_free
{
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
static char * malloc(const size_type bytes)
{ return reinterpret_cast<char *>(std::malloc(bytes)); }
static void free(char * const block)
{ std::free(block); }
};
namespace details
{
template <typename SizeType>
class PODptr
{
public:
typedef SizeType size_type;
private:
char * ptr;//指向的Block
size_type sz;//指向的所有Block的字节数
char * ptr_next_size() const
{ return (ptr + sz - sizeof(size_type)); }
char * ptr_next_ptr() const
{
return (ptr_next_size() -
::boost::details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value);
}
public:
PODptr(char * const nptr, const size_type nsize)
:ptr(nptr), sz(nsize) { }
PODptr()
:ptr(0), sz(0) { }
bool valid() const { return (begin() != 0); }
void invalidate() { begin() = 0; }
char * & begin() { return ptr; }
char * begin() const { return ptr; }
char * end() const { return ptr_next_ptr(); }
size_type total_size() const { return sz; }
size_type element_size() const
{
return (sz - sizeof(size_type) -
::boost::details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value);
}
size_type & next_size() const
{ return *(reinterpret_cast<size_type *>(ptr_next_size())); }
char * & next_ptr() const
{ return *(reinterpret_cast<char **>(ptr_next_ptr())); }
PODptr next() const
{ return PODptr<size_type>(next_ptr(), next_size()); }
void next(const PODptr & arg) const
{
next_ptr() = arg.begin();
next_size() = arg.total_size();
}
};
} // namespace details
template <typename SizeType>
class simple_segregated_storage
{
public:
typedef SizeType size_type;
private:
//不允许拷贝构造和赋值
simple_segregated_storage(const simple_segregated_storage &);
void operator=(const simple_segregated_storage &);
static void * try_malloc_n(void * & start, size_type n,
size_type partition_size);
protected:
void * first;
void * find_prev(void * ptr);
//得到ptr所指向的地址
static void * & nextof(void * const ptr)
{ return *(static_cast<void **>(ptr)); }
public:
simple_segregated_storage()
:first(0) { }
static void * segregate(void * block,
size_type nsz, size_type npartition_sz,
void * end = 0);
//nsz是npartition_sz的倍数,nsz是chunk的总字节数,npartition_sz是chunk的数量
//对block细切,然后把该block加入到free list中的最前面去
void add_block(void * const block,
const size_type nsz, const size_type npartition_sz)
{
first = segregate(block, nsz, npartition_sz, first);
}
//nsz是npartition_sz的倍数
//对block细切,然后把该block加入到free list中合适的位置上
void add_ordered_block(void * const block, const size_type nsz, const size_type npartition_sz)
{
//找到block应该加入的地方
void * const loc = find_prev(block);
if (loc == 0)//加入到free list中的最前面
add_block(block, nsz, npartition_sz);
else//挂链,加入到free list的中间
nextof(loc) = segregate(block, nsz, npartition_sz, nextof(loc));
}
bool empty() const { return (first == 0); }
//直接将free list最前面的空闲内存分配
void * malloc()
{
void * const ret = first;
//调整free list的头指针
first = nextof(first);
return ret;
}
//chunk必须是malloc()函数返回
//把chunk收回,放到free list的头部
void free(void * const chunk)
{
//把chunk加入free list的头部
nextof(chunk) = first;
first = chunk;
}
//chunk必须是malloc()函数返回
//把chunk收回,放到free list中合适的位置
void ordered_free(void * const chunk)
{
//找到chunk应该加入的地方
void * const loc = find_prev(chunk);
//把chunk加入free list中合适的位置
if (loc == 0)//头部
free(chunk);
else
{//挂链,加入到free list的中间
nextof(chunk) = nextof(loc);
nextof(loc) = chunk;
}
}
// Note: if you're allocating/deallocating n a lot, you should
// be using an ordered pool.
void * malloc_n(size_type n, size_type partition_size);
//chunks是本对象分配的malloc_n函数分配的空间
//并且n和partition_size两个参数也要一致
//释放chunks的内存
void free_n(void * const chunks, const size_type n,
const size_type partition_size)
{
add_block(chunks, n * partition_size, partition_size);
}
//同上函数
void ordered_free_n(void * const chunks, const size_type n,
const size_type partition_size)
{
add_ordered_block(chunks, n * partition_size, partition_size);
}
};
//函数:simple_segregated_storage::find_prev
//遍历free list,返回如果ptr加入到free list中,ptr的前一个chunk的位置(按照地址的高低排序)
//返回,表明ptr应该在free list头部
template <typename SizeType>
void * simple_segregated_storage<SizeType>::find_prev(void * const ptr)
{
//如果free list为空,或者first > ptr,返回(表明ptr应该加在free list头部)
if (first == 0 || std::greater<void *>()(first, ptr))
return 0;
void * iter = first;
while (true)
{
if (nextof(iter) == 0 || std::greater<void *>()(nextof(iter), ptr))
return iter;
iter = nextof(iter);
}
}
//函数:simple_segregated_storage::segregate
//要求:
//1. npartition_sz >= sizeof(void *)
//2. nsz >= npartition_sz
//3. npartition_sz = sizeof(void *) * i
//将一块block细切(以block开头,下一个block的开头是end),然后将其挂到end的前面
//该block共sz个字节,每个chunk有partition_sz字节
template <typename SizeType>
void * simple_segregated_storage<SizeType>::segregate(
void * const block,
const size_type sz,
const size_type partition_sz,
void * const end)
{
//计算出block中最后一个有效的chunk的指针
//old == block + partition_sz * i
char * old = static_cast<char *>(block)
+ ((sz - partition_sz) / partition_sz) * partition_sz;
//令它指向下一个block的开头
nextof(old) = end;
//如果该block只有一个chunk的空间(sz == partition_sz)
if (old == block) return block;
//从后往前,将这个block中的每个chunk挂链,形成一个单向链表
for (char * iter = old - partition_sz ; iter != block ; old = iter, iter -= partition_sz)
nextof(iter) = old;
nextof(block) = old;
return block;
}
//函数:simple_segregated_storage::try_malloc_n
//要求:
//1. n > 0
//2. start != 0
//3. nextof(start) != 0
//尝试在free list中,从start处(start不包括)开始,找到n个临近的大小为partition_size的chunk,
//成功返回最后一个chunk的指针.这样,空闲的内存区域为[start,返回值](但是不能使用,因为没有分配)
//失败返回,不分配任何内存.start会被改变为最后一个尝试的chunk块的指针
template <typename SizeType>
void * simple_segregated_storage<SizeType>::try_malloc_n(
void * & start, size_type n, const size_type partition_size)
{
void * iter = nextof(start);
while (--n != 0)
{
void * next = nextof(iter);
if (next != static_cast<char *>(iter) + partition_size)
{
//next为, 或者不连续
start = iter;
return 0;
}
//iter前进,继续判断
iter = next;
}
return iter;
}
//函数:simple_segregated_storage::malloc_n
//尝试在free list中,从start处(start不包括)开始,找到n个临近的大小为partition_size的chunk,
//成功返回最后一个chunk的指针.这样,空闲的内存区域为[start,返回值](但是不能使用,因为没有分配)
//失败返回,不分配任何内存.
template <typename SizeType>
void * simple_segregated_storage<SizeType>::malloc_n(const size_type n,
const size_type partition_size)
{
void * start = &first;
void * iter;
do
{
if (nextof(start) == 0)
return 0;
//注意:并不是死循环,start在try_malloc_n返回时会被改变
iter = try_malloc_n(start, n, partition_size);
} while (iter == 0);
void * const ret = nextof(start);
nextof(start) = nextof(iter);
return ret;
}
template <typename UserAllocator>
class pool: protected simple_segregated_storage<
typename UserAllocator::size_type>
{
public:
typedef UserAllocator user_allocator;
typedef typename UserAllocator::size_type size_type;
typedef typename UserAllocator::difference_type difference_type;
private:
BOOST_STATIC_CONSTANT(unsigned, min_alloc_size =
(::boost::details::pool::ct_lcm<sizeof(void *), sizeof(size_type)>::value) );
// Returns 0 if out-of-memory
// Called if malloc/ordered_malloc needs to resize the free list
void * malloc_need_resize();
void * ordered_malloc_need_resize();
protected:
details::PODptr<size_type> list;
const size_type requested_size;
size_type next_size;
simple_segregated_storage<size_type> & store() { return *this; }//向上转型
const simple_segregated_storage<size_type> & store() const { return *this; }//向上转型
details::PODptr<size_type> find_POD(void * const chunk) const;//查找chunk是哪个POD分配的
//判断chunk是否在block i中,其中block i中有sizeof_i个chunk
static bool is_from(void * const chunk, char * const i,
const size_type sizeof_i)
{
//i <= chunk < i+sizeof_i
std::less_equal<void *> lt_eq;
std::less<void *> lt;
return (lt_eq(i, chunk) && lt(chunk, i + sizeof_i));
}
size_type alloc_size() const
{
const unsigned min_size = min_alloc_size;
return ::boost::details::pool::lcm<size_type>(requested_size, min_size);
}
static void * & nextof(void * const ptr)
{ return *(static_cast<void **>(ptr)); }
public:
// The second parameter here is an extension!
// pre: npartition_size != 0 && nnext_size != 0
explicit pool(const size_type nrequested_size,
const size_type nnext_size = 32)
:list(0, 0), requested_size(nrequested_size), next_size(nnext_size)
{ }
~pool() { purge_memory(); }
bool release_memory();//释放未被分配的block,返回true成功
bool purge_memory();//释放所有block,返回true成功
// These functions are extensions!
size_type get_next_size() const { return next_size; }
void set_next_size(const size_type nnext_size) { next_size = nnext_size; }
//所有的分配函数失败时返回
void * malloc()
{
// Look for a non-empty storage
if (!store().empty())
return store().malloc();
return malloc_need_resize();
}
void * ordered_malloc()
{
// Look for a non-empty storage
if (!store().empty())
return store().malloc();
return ordered_malloc_need_resize();
}
void * ordered_malloc(size_type n);//分配连续的n个chunk
//chunk必须是*this.malloc()分配的
void free(void * const chunk){ store().free(chunk); }
//同上
void ordered_free(void * const chunk){ store().ordered_free(chunk); }
//同上
void free(void * const chunks, const size_type n)
{
const size_type partition_size = alloc_size();//chunk的大小
const size_type total_req_size = n * requested_size;//总字节数量
const size_type num_chunks = total_req_size / partition_size +//chunk的数量
((total_req_size % partition_size) ? true : false);//为什么不写或者???
store().free_n(chunks, num_chunks, partition_size);
}
//同上
void ordered_free(void * const chunks, const size_type n)
{
const size_type partition_size = alloc_size();
const size_type total_req_size = n * requested_size;
const size_type num_chunks = total_req_size / partition_size +
((total_req_size % partition_size) ? true : false);
store().ordered_free_n(chunks, num_chunks, partition_size);
}
//判断chunk是否是本对象分配的
bool is_from(void * const chunk) const
{
return (find_POD(chunk).valid());
}
};
template <typename UserAllocator>
bool pool<UserAllocator>::release_memory()
{
bool ret = false;
//block队列上当前和过去的iterator pair
details::PODptr<size_type> ptr = list;
details::PODptr<size_type> prev;
//chunk队列上当前和过去的iterator pair
//注意:prev_free指向的是chunk队列上当前block之前的空闲chunk
void * free = this->first;
void * prev_free = 0;
const size_type partition_size = alloc_size();//每个chunk的大小
//遍历搜索所有的已分配的block
while (ptr.valid())
{
if (free == 0) return ret;
// At this point:
// ptr points to a valid memory block
// free points to either:
// 0 if there are no more free chunks
// the first free chunk in this or some next memory block
// prev_free points to either:
// the last free chunk in some previous memory block
// 0 if there is no such free chunk
// prev is either:
// the PODptr whose next() is ptr
// !valid() if there is no such PODptr
// If there are no more free memory chunks, then every remaining
// block is allocated out to its fullest capacity, and we can't
// release any more memory
// We have to check all the chunks. If they are *all* free (i.e., present
// in the free list), then we can free the block.
bool all_chunks_free = true;
// Iterate 'i' through all chunks in the memory block
// if free starts in the memory block, be careful to keep it there
void * saved_free = free;
for (char * i = ptr.begin(); i != ptr.end(); i += partition_size)
{
// If this chunk is not free
if (i != free)
{
// We won't be able to free this block
all_chunks_free = false;
// free might have travelled outside ptr
free = saved_free;
// Abort searching the chunks; we won't be able to free this
// block because a chunk is not free.
break;
}
// We do not increment prev_free because we are in the same block
free = nextof(free);
}
// post: if the memory block has any chunks, free points to one of them
// otherwise, our assertions above are still valid
const details::PODptr<size_type> next = ptr.next();
if (!all_chunks_free)
{
if (is_from(free, ptr.begin(), ptr.element_size()))
{
std::less<void *> lt;
void * const end = ptr.end();
do
{
prev_free = free;
free = nextof(free);
} while (free && lt(free, end));
}
// This invariant is now restored:
// free points to the first free chunk in some next memory block, or
// 0 if there is no such chunk.
// prev_free points to the last free chunk in this memory block.
// We are just about to advance ptr. Maintain the invariant:
// prev is the PODptr whose next() is ptr, or !valid()
// if there is no such PODptr
prev = ptr;
}
else
{
// All chunks from this block are free
// Remove block from list
if (prev.valid())
prev.next(next);
else
list = next;
// Remove all entries in the free list from this block
if (prev_free != 0)
nextof(prev_free) = free;
else
this->first = free;
// And release memory
UserAllocator::free(ptr.begin());
ret = true;
}
// Increment ptr
ptr = next;
}
return ret;
}
//释放所有已分配的和未分配的内存
template <typename UserAllocator>
bool pool<UserAllocator>::purge_memory()
{
details::PODptr<size_type> iter = list;
if (!iter.valid())
return false;
do
{
// hold "next" pointer
const details::PODptr<size_type> next = iter.next();
// delete the storage
UserAllocator::free(iter.begin());
// increment iter
iter = next;
} while (iter.valid());
list.invalidate();
this->first = 0;
return true;
}
template <typename UserAllocator>
void * pool<UserAllocator>::malloc_need_resize()
{
//分配新的区域做block
const size_type partition_size = alloc_size();//chunk的大小
const size_type POD_size = next_size * partition_size +//
::boost::details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
//分配空间
char * const ptr = UserAllocator::malloc(POD_size);
if (ptr == 0) return 0;
const details::PODptr<size_type> node(ptr, POD_size);
next_size <<= 1;//左移位
//初始化新的空间
store().add_block(node.begin(), node.element_size(), partition_size);
//挂链
node.next(list);
list = node;
//此时有剩余空间,直接调用分配函数
return store().malloc();
}
template <typename UserAllocator>
void * pool<UserAllocator>::ordered_malloc_need_resize()
{
//分配新的区域做block
const size_type partition_size = alloc_size();//chunk的大小
const size_type POD_size = next_size * partition_size +
::boost::details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
//分配空间
char * const ptr = UserAllocator::malloc(POD_size);
if (ptr == 0) return 0;
const details::PODptr<size_type> node(ptr, POD_size);
next_size <<= 1;//左移位
//初始化新的空间
store().add_block(node.begin(), node.element_size(), partition_size);
//找到合适的地方挂链
if (!list.valid() || std::greater<void *>()(list.begin(), node.begin()))
{
node.next(list);
list = node;
}
else
{
details::PODptr<size_type> prev = list;
while (true)
{
if (prev.next_ptr() == 0 || std::greater<void *>()(prev.next_ptr(), node.begin()))
break;
prev = prev.next();
}
node.next(prev.next());
prev.next(node);
}
//此时有剩余空间,直接调用分配函数
return store().malloc();
}
template <typename UserAllocator>
void * pool<UserAllocator>::ordered_malloc(const size_type n)
{
const size_type partition_size = alloc_size();
const size_type total_req_size = n * requested_size;
const size_type num_chunks = total_req_size / partition_size +
((total_req_size % partition_size) ? true : false);
void * ret = store().malloc_n(num_chunks, partition_size);
if (ret) return ret;
//没剩余空间,分配
using std::max;
next_size = max <size_type>(next_size, num_chunks);
const size_type POD_size = next_size * partition_size +
boost::details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
//分配
char * const ptr = UserAllocator::malloc(POD_size);
if (ptr == 0) return 0;
const details::PODptr<size_type> node(ptr, POD_size);
// Split up block so we can use what wasn't requested
// (we can use "add_block" here because we know that
// the free list is empty, so we don't have to use
// the slower ordered version)
if (next_size > num_chunks)
store().add_block(node.begin() + num_chunks * partition_size,
node.element_size() - num_chunks * partition_size, partition_size);
next_size <<= 1;
//找到合适的地方挂链
if (!list.valid() || std::greater<void *>()(list.begin(), node.begin()))
{
node.next(list);
list = node;
}
else
{
details::PODptr<size_type> prev = list;
while (true)
{
// if we're about to hit the end or
// if we've found where "node" goes
if (prev.next_ptr() == 0
|| std::greater<void *>()(prev.next_ptr(), node.begin()))
break;
prev = prev.next();
}
node.next(prev.next());
prev.next(node);
}
// and return it.
return node.begin();
}
template <typename UserAllocator>
details::PODptr<typename pool<UserAllocator>::size_type>
pool<UserAllocator>::find_POD(void * const chunk) const
{
// We have to find which storage this chunk is from.
details::PODptr<size_type> iter = list;
while (iter.valid())
{
if (is_from(chunk, iter.begin(), iter.element_size()))
return iter;
iter = iter.next();
}
return iter;
}
template <typename T, typename UserAllocator>
class object_pool: protected pool<UserAllocator>
{
public:
typedef T element_type;
typedef UserAllocator user_allocator;
typedef typename pool<UserAllocator>::size_type size_type;
typedef typename pool<UserAllocator>::difference_type difference_type;
protected:
pool<UserAllocator> & store() { return *this; }
const pool<UserAllocator> & store() const { return *this; }
// for the sake of code readability :)
static void * & nextof(void * const ptr)
{ return *(static_cast<void **>(ptr)); }
public:
// This constructor parameter is an extension!
explicit object_pool(const size_type next_size = 32)
:pool<UserAllocator>(sizeof(T), next_size) { }
~object_pool();
// Returns 0 if out-of-memory
element_type * malloc()
{ return static_cast<element_type *>(store().ordered_malloc()); }
void free(element_type * const chunk)
{ store().ordered_free(chunk); }
bool is_from(element_type * const chunk) const
{ return store().is_from(chunk); }
element_type * construct()
{
element_type * const ret = malloc();
if (ret == 0)
return ret;
try { new (ret) element_type(); }//placement new
catch (...) { free(ret); throw; }
return ret;
}
// Include automatically-generated file for family of template construct()
// functions
#ifndef BOOST_NO_TEMPLATE_CV_REF_OVERLOADS
# include <boost/pool/detail/pool_construct.inc>
#else
# include <boost/pool/detail/pool_construct_simple.inc>
#endif
void destroy(element_type * const chunk)
{
chunk->~T();
free(chunk);
}
// These functions are extensions!
size_type get_next_size() const { return store().get_next_size(); }
void set_next_size(const size_type x) { store().set_next_size(x); }
};
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();
}
}//namespace kimi_boost
#endif//__KIMI_BOOST_POOL
Test code
void pool_test()
{
using namespace std;
{
kimi_boost::object_pool<string> p;
string* pi[100];
for (int i = 0; i < 100; ++i)
{
pi[i]= p.construct();
}
pi[1]->push_back('d');
for (int i = 0; i < 100; ++i)
{
p.destroy(pi[i]);
}
pi[2]->push_back('a');
string* pstring = p.construct();
bool isfrom = p.is_from(pstring);
isfrom = p.is_from( pstring + 100 );
p.destroy(pstring);
}
{
kimi_boost::pool<> p(sizeof(int));
int* pi[100];
for (int i = 0; i < 100; ++i)
{
pi[i]= (int*)p.malloc();
}
for (int i = 0; i < 100; ++i)
{
p.free(pi[i]);
}
}
{
kimi_boost::pool<> p(sizeof(char));
char* pstr = (char*)p.ordered_malloc(20);
memset(pstr,'/0',20);
p.ordered_free(pstr,20);
}
}
Output
none