目录
一,定长池介绍
这个模块是一个快速生成特定大小内存池的模块。是后面实现高并发内存池的重要模块之一。
申请空间时使用的还是malloc函数,但是在后面的测试中会比单纯的malloc更加快速,效率更高。
二,基本结构
三成员
T*_memory:指向大块空间的头部。
int remainSize:标记大块空间的大小,判断是否需要重新申请空间
void*_freelist:delete空间时要将free的空间头插到到这个链表上。
两函数
T* New():用于申请空间,生成T类型对象,优先使用free_list上的空间。
void delete(T*object):释放空间的作用,释放的空间要头插到free_list链表里。
代码结构:
class FixedPoll
{
public:
T* New()
{
//1,优先使用_freeList里的内存空间
if (_freelist)
{
}
//2,当_freeList上没有free的地址
else
{
// 内存不足时先申请大块空间
if (_remainSize < sizeof(T))
{
}
else
{
}
}
}
void Delete(T* obj)
{
//使用头插的方式来记录free后的对象的地址
}
private:
T* _memory = nullptr;//指向大块的内存
int _remainSize = 0;//用于标记内存的剩余大小
void* _freeList = nullptr;//用于存放释放后的内存地址
};
三,具体实现
1,New的具体实现
T* New()
{
//1,优先使用_freeList里的内存空间
//先定义一个指针对象
T* obj = nullptr;
if (_freeList)
{
//前面的指针大小空间记录下一个节点的地址
void* next = *(void**)_freeList;
//将空间读取出来给obj对象
obj = (T*)_freeList;
//freeList到下一个节点上
_freeList = next;
}
//2,当_freeList上没有free的地址
else
{
//先确定好空间至少要大于指针大小
int objSize = sizeof(T*) > sizeof(T) ? sizeof(T*) : sizeof(T);
// 内存小于sizeof(T)先申请大块空间
if (_remainSize < objSize)
{
//申请128K大小的内存空间
_remainSize = 128 * 1024;
_memory = (char*)malloc(128 * 1024);
if (_memory == nullptr)
{
throw std::bad_alloc();
}
//将前面的sizeof(T)大小的内存分配给obj
obj = (T*)_memory;
_memory += objSize;
_remainSize -= objSize;
}
//
else
{
//内存空间不小于T时
obj = (T*)_memory;
_memory += objSize;
_remainSize -= objSize;
}
}
return obj;
}
实现New功能的注意点:
1,如果free_list存在时要优先使用free_list里面的空间。
2,要保证obj对象的大小大于指针大小,这是为了后面的free_list的实现。
2,Delete的具体实现
void Delete(T* obj)
{
//使用头插的方式来记录free后的对象的地址
//实现头插的方式就是先取出obj的前四个或者八个字节大小的空间存放_freeList的地址,然后再让_freeList指向头部。
//注意点:要保证obj的大小至少为四个或者八个字节,所以在new时就要确定好。
*(void**)obj = _freeList;
_freeList = obj;
}
Delete实现的注意点:
1,如何适应不同的平台取出的指针的大小都是合法的?使用*(void**)强转的方式。
2,没有next指针如何链接:使用头插的方式。
四,测试
测试代码:
void TestObjectPool()
{
// 申请释放的轮次
const size_t Rounds = 3;
// 每轮申请释放多少次
const size_t N = 100000;
//使用new和delete测试
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();
FixedPoll<TreeNode> 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的速度。