一、前言
内存池化技术简单来说就是提前向系统申请一大块空间,后面需要空间的时候直接去大块空间中取,就不用频繁的向系统要,降低系统频繁建连的资源开销。如你要去河边挑水喝,每次想喝的时候都得去河边挑水,但如果你在加旁边挖一个小池塘,你直接把谁灌进去,下次你要喝水的时候就不用去河边挑水,直接在家门口就能喝到,这就很方便。
二、定长内存池简介
定长内存池就是内存池被申请后被提前分块,每次获取的小内存块空间是固定大小的,故称之为定长内存池。
三、定长内存池成员变量及成员函数声名
定长内存池中包含三个成员变量:1,char* _memory(用char类型指针,一次取1字节空间,方便后面取空间)作为定长内存池起始地址。 2,size_t _remainbytes表示内存池中剩余的空间大小 . 3,void* _freelist表示向内存池中释放的空间地址。
定长内存池中包含二个成员函数:1,T* NEW()用于向定长内存池申请新空间 2,void Delete(T* obj)用于向定长内存池释放空间。居然代码如下:
template
class opjectpool
{
public:
T* NEW();//用于向定长内存池申请新空间
void Delete(T* obj);//用于向定长内存池释放空间
private:
char* _memory = nullptr;//定长内存池起始地址,用char做刀,切空间好切,一次切1,比切int切4好用
size_t _remainbytes = 0;//用于确定内存剩余多少空间
void* _freelist = nullptr;//释放空间的头指针
};
四、成员函数定义
T* NEW()//申请空间
{
T* obj = nullptr;
if (_freelist)//如果有释放的空间,优先使用释放的空间
{
void* next = (void*)_freelist;
obj = (T*)_freelist;
_freelist = next;
}
else
{
//第一次或内存空间不足,直接向内存申请空间
if (_remainbytes < sizeof(T))
{
_remainbytes = 128 * 1024;
_memory = (char*)SystemAlloc(_remainbytes >> 13);//不走malloc直接上堆上要
if (_memory == nullptr)//申请失败抛异常
{
throw std::bad_alloc();
}
}
//从内存池中取空间
obj = (T*)_memory;
size_t objsize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);//解决T空间小于指针情况
_memory += objsize;//?是否会占用后面不是他的空间?
_remainbytes -= sizeof(T);
}
//定位NEW,显示调用T的构造函数初始化
new(obj)T;
return obj;
}
五、效率分析
我们通过对比向系统直接new和向定长内存池重复申请释放空间所用的运行时间进行效率分析,具体测试函数代码如下:
struct TreeNode
{
int _val;
TreeNode* _left;
TreeNode* _right;
TreeNode()
:_val(0)
, _left(nullptr)
, _right(nullptr)
{}
};
static void TestObjectPool()
{
// 申请释放的轮次
const size_t Rounds = 3;
// 每轮申请释放多少次
const size_t N = 10000;
size_t begin1 = clock();
std::vector<TreeNode*> v1;
v1.reserve(N);
for (size_t j = 0; j < Rounds; ++j)
{
for (int i = 0; i < N; ++i)
{
v1.push_back(new TreeNode);
}
for (int i = 0; i < N; ++i)
{
delete v1[i];
}
v1.clear();
}
size_t end1 = clock();
opjectpool TNPool;
size_t begin2 = clock();
std::vector<TreeNode*> v2;
v2.reserve(N);
for (size_t j = 0; j < Rounds; ++j)
{
for (int i = 0; i < N; ++i)
{
v2.push_back(TNPool.NEW());
}
for (int i = 0; i < N; ++i)
{
TNPool.Delete(v2[i]);
}
v2.clear();
}
size_t end2 = clock();
cout << “new cost time:” << end1 - begin1 << endl;
cout << “object pool cost time:” << end2 - begin2 << endl;
}
运行上面的函数,可以得到下列结果:
从上面的结果可以看出向定长内存池申请空间的运行时间明显少于向系统直接new空间,因此定长内存池的效率是非常高的。