pool
boost.pool
boost.pool
库基于简单分隔存储的思想实现了一个快速、紧凑的内存池
不仅能够管理大量对象,还可以用作STL的内存分配器,在需要大量分配或释放小对象时效率很高,且不需要考虑delete
包含4个组成部分
- 简单
pool
- 分配类实例
object_pool
- 单件内存池
singleton_pool
- 用于标准库
pool_alloc
pool
最简单和最容易使用的内存池类,返回一个简单数据类型POD的内存指针,位于命名空间boost
#include<boost/pool/pool.hpp>
using namespace boost;
类原型
template<typename UserAllocator=default_user_allocator_new_delete>
class pool{
public:
explicit pool(size_type requested_size); // 可以指定内存块大小,而不是内存池大小
~pool();
size_type get_requested_size()const; // 分配内存块大小
void* malloc();
void* ordered_malloc();
void* ordered_malloc(size_type n);
bool is_from(void* chunk)const;
void free(void* chunk);
void ordered_free(void* chunk);
void free(void* chunk, size_type n);
void ordered_free(void* chunk, size_type n);
bool release_memory();
bool purge_memory();
};
模板类型参数UserAllocator
使用默认的内存分配器,基于new[]
和delete[]
实现
malloc()
和ordered_malloc()
从内存池中分配内存块,大小由构造函数参数requested_size
指定,若分配失败会返回空指针,不抛出异常
malloc()
从内存池中任意分配一个内存块,而ordered_malloc()
在分配的同时合并空闲块链表,带参数的ordered_malloc()
可以连续分配n块内存
is_from()
测试内存块是否属于当前内存池
一般情况下,内存池会自动管理内存分配,不需要调用free()
,除非用户认为内存池空间不足,必须先释放一定的内存
release_memory()
释放内存池中所有未被分配的内存,已分配的不受影响
purge_memory()
强制释放内存池持有的所有内存,析构函数就是调用的该函数
示例如下:
int main(){
pool<> p(sizeof(int)); // 一个可分配int的内存池
int* p1= static_cast<int*>(p.malloc()); // 转换void*
if(p1!=nullptr){
}
assert(p1.is_from(p));
p.free(p1);
for(int i=0; i<100; ++i){ // 连续分配大量的内存
p.ordered_malloc(10);
}
}
pool
只能用于普通数据类型的内存池,不能应用于复杂类型和对象,因为其只分配内存,不构造对象
object_pool
应用于类实例的内存池,功能与pool
类似,但其会在析构时对所有已分配的内存块调用析构函数
#include<boost/pool/object_pool.hpp>
using namespace boost;
类原型
template<typename T, typename UserAllocator>
class object_pool:protected pool<UserAllocator>{
public:
typedef T element_type;
public:
object_pool();
~object_pool();
element_type* malloc();
void free(element_type* p);
bool is_from(element_type* p)const;
element_type* construct(...);
void destroy(element_type* p);
};
object_pool
的模板类型参数T
指定要分配的元素类型,要求其析构函数不抛出异常
一旦指定了类型,object_pool
对象就不能再用于分配其他类型
construct()
有多个重载形式,先调用malloc()
分配内存,再根据参数调用类的构造函数
destroy()
先调用对象的析构函数,再用free()
释放内存块
malloc()
和free()
表示分配和释放一块类型为T*
的内存块
只有在当前内存池中分配的内存块才能被free()
释放
这两个函数被调用时不调用类构造函数和析构函数,操作的是原始内存块,里面的值是未定义的
示例如下:
struct demo{
public:
int a,b,c;
demo(int x=1, int y=2, int z=3):a(x),b(y),c(z){}
};
int main(){
object_pool<demo> p;
auto p1= p.malloc();
assert(p.is_from(p1));
// p1指向的内存未初始化
assert(p->a!=1 || p->b!=2 || p->c!=3);
p1= p.construct(7,8,9);
assert(p->a==7);
object_pool<string> pstr;
for(int i=0; i<10; ++i){
string* p2= pstr.construct("hello object_pool");
std::cout<<*p2<<std::endl;
}
}
默认情况下,使用object_pool
只能接收3个参数来创建对象
使用C++标准的可变参数模板解决该问题
template<typename T, typename ... Args>
inline typename T::element_type* construct(T& t, Args&& ... args){
typename T::element_type* mem= t.malloc();
assert(mem!=0);
new (mem) typename T::element_type(std::forward<Args>(args)...); // 完美转发
return mem;
}
// 使用
object_pool<demo> p;
auto p1= construct(p, 1,2,3,4);
singleton_pool
与pool类似,用于分配POD,但是该类对象是一个单件
#include<boost/pool/singleton_pool.hpp>
using namespace boost;
默认使用boost.thread
库提供线程安全,所以需要将其链接boost_thread库
若不使用多线程,可在头文件前定义BOOST_POOL_NO_MT
类原型
template<typename Tag, unsigned RequestedSize>
class Singleton_pool{
public:
static bool is_from(void* ptr);
static void* malloc();
static void* ordered_malloc();
static void* ordered_malloc(size_type n);
static void free(void* ptr);
static void ordered_free(void* ptr);
static void free(void* ptr, std::size_t n);
static void ordered_free(void* ptr, size_type n);
static bool release_memory();
static bool purge_memory();
};
模板类型参数Tag
用于标记不同的单件,可以是空类,甚至可以只进行声明
参数RequestedSize
等同于pool
中的requested_size
,用来指示内存块大小
因为singleton_pool是单件,所有其声明周期与整个程序一致,除非手动释放
示例如下:
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();
}