1. 内存池技术优点
提前分配,可减少内存的分配和释放的开销,提高效率; 减少内存碎片化;
2. pool
只能用于普通数据类型如 int,double等的内存池;
// boost库源码:
template<typename UserAllocator>
class pool
{
public:
...
// construct/copy/destruct
//指示每次pool分配内存块的大小(不是内存池大小);
explicit pool(const size_type s, const size_type = 32, const size_type m = 0) : chunk_size(s), max_alloc_size(m) {}
~pool()
{
purge_memory();
}
bool release_memory()
{
bool ret = free_list.empty() ? false : true;
for(std::set<void*>::iterator pos = free_list.begin(); pos != free_list.end(); ++pos)
{
(user_allocator::free)(static_cast<char*>(*pos));
}
free_list.clear();
return ret;
}
//强制释放pool池内存;
bool purge_memory()
{
bool ret = free_list.empty() && used_list.empty() ? false : true;
for(std::set<void*>::iterator pos = free_list.begin(); pos != free_list.end(); ++pos)
{
(user_allocator::free)(static_cast<char*>(*pos));
}
free_list.clear();
for(std::set<void*>::iterator pos = used_list.begin(); pos != used_list.end(); ++pos)
{
(user_allocator::free)(static_cast<char*>(*pos));
}
used_list.clear();
return ret;
}
//失败返回0;
void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
{
void* ret;
if(free_list.empty())
{
//空闲链表为空,说明没有分配过;执行内存申请;
ret = (user_allocator::malloc)(chunk_size);
VALGRIND_MAKE_MEM_UNDEFINED(ret, chunk_size);
}
else
{
//空闲链表非空,直接从空闲链表取块;
ret = *free_list.begin();
free_list.erase(free_list.begin());
VALGRIND_MAKE_MEM_UNDEFINED(ret, chunk_size);
}
//分配后,这块内存被用了;加入到已使用的内存块链表;
used_list.insert(ret);
return ret;
}
void * ordered_malloc()
{
return (this->malloc)();
}
//连续分配n块内存;
void * ordered_malloc(size_type n)
{
if(max_alloc_size && (n > max_alloc_size))
return 0;
void* ret = (user_allocator::malloc)(chunk_size * n);
used_list.insert(ret);
return ret;
}
//仅仅从已使用链表移除; 并没有真正真正的释放内存;
void free BOOST_PREVENT_MACRO_SUBSTITUTION(void *const chunk)
{
BOOST_ASSERT(used_list.count(chunk) == 1);
BOOST_ASSERT(free_list.count(chunk) == 0);
used_list.erase(chunk);
free_list.insert(chunk);
VALGRIND_MAKE_MEM_NOACCESS(chunk, chunk_size);
}
void ordered_free(void *const chunk)
{
return (this->free)(chunk);
}
void free BOOST_PREVENT_MACRO_SUBSTITUTION(void *const chunk, const size_type)
{
BOOST_ASSERT(used_list.count(chunk) == 1);
BOOST_ASSERT(free_list.count(chunk) == 0);
used_list.erase(chunk);
(user_allocator::free)(static_cast<char*>(chunk));
}
void ordered_free(void *const chunk, const size_type n)
{
(this->free)(chunk, n);
}
//测试trunk块是否是从这个内存池分配的;
bool is_from(void *const chunk) const
{
return used_list.count(chunk) || free_list.count(chunk);
}
protected:
//chunk_size:内存块大小
size_type chunk_size, max_alloc_size;
//空闲链表,已使用的链表
std::set<void*> free_list, used_list;
};
#endif
} // namespace boost
使用示例:
{
//内存池中 每个内存块的大小为sizeof(int),使用默认的分配器;
pool<> pl(sizeof(int));
//假如项目最大只想用10个内存块
#define MAX_POOL_BLK 10
int *p[MAX_POOL_BLK] = {0};
for(int i = 0; i < MAX_POOL_BLK; ++i){
p[i] = static_cast<int *>(pl.malloc());//这十个内存块都是实际调用系统函数分配出来的;
}
//到这里,pool内存池中拥有10个 每个大小为 sizeof(int) 的内存块了; 并且都被占用了;
for(int i = 0; i < MAX_POOL_BLK; ++i){
pl.free(p[i]); //并没有真正释放内存,仅仅是将内存块变成空闲的了;
}
//到这里,pool内存池中依然拥有10个 每个大小为 sizeof(int) 的内存块; 但是内存块都是空闲的;
//下次需要用到一个内存块,可以直接调用 pl.malloc();
//在需要的内存块数量不超过上述10个时,使用的是之前分配好的空闲的; 当大于10个时(可扩容),才会调用系统函数真正申请内存空间;
cout << "is_from: " << pl.is_from(p[0]) << endl;
//接下来,需要时 p[i] = static_cast<int *>(pl.malloc())
//不需要时 pl.free(p[i]);
//离开作用域时自动调用 pl.purge_memory();释放内存;
}
3. object_pool
用于类实例(对象)的内存池;
继承自pool, 其中多了 construct()和destroy()函数; 可实现内存分配+类对象构造析构调用;
//来自boost库源码
template <typename T, typename UserAllocator>
class object_pool: protected pool<UserAllocator>
{ //!
...
protected:
pool<UserAllocator> & store()
{
return *this;
}
public:
explicit object_pool(const size_type arg_next_size = 32, const size_type arg_max_size = 0)
:
pool<UserAllocator>(sizeof(T), arg_next_size, arg_max_size)
{
}
~object_pool();
// Returns 0 if out-of-memory.
element_type * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
{
return static_cast<element_type *>(store().ordered_malloc());
}
void free BOOST_PREVENT_MACRO_SUBSTITUTION(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)(); //先调用 element_type * malloc() 分配内存块;
if (ret == 0)
return ret;
try { new (ret) element_type(); } //再在内存块上使用传入的参数调用类的构造函数;
catch (...) { (free)(ret); throw; }
return ret;
}
#ifndef BOOST_NO_TEMPLATE_CV_REF_OVERLOADS
# include <boost/pool/detail/pool_construct.ipp>
#else
# include <boost/pool/detail/pool_construct_simple.ipp>
#endif
#endif
void destroy(element_type * const chunk)
{
chunk->~T(); //先调用析构
(free)(chunk);//再归还内存块;
}
...
};
使用示例:
{
class demo_calss
{
public:
int a,b,c;
demo_calss(int x=1, int y=2, int z=3):a(x),b(y),c(z){}
};
// 对象内存池
object_pool<demo_calss> pl;
demo_calss *p = pl.construct(5,6,7);
cout << p->a << " " << p->b << " " << p->c << endl;
pl.destroy(p);//调用类析构,同时归还内存块
//到这里,对象内存池中还有一个空闲的内存块;
//作用域结束,调用内存池析构真正释放所有内存;
}
object_pool类的实现提供了实际用途内存池的关键,只需在其基础上增添一些内容即可实现一个可循环的内存池!!;