设计思想
先和系统申请一大块内存空间,然后每次用完用链表将回收的内存连起来,下次继续使用他们
固定大小的内存申请释放需求
特点:
1、性能达到极致
2、不考虑内存碎片等问题。
代码解读:
先设置三个成员memeory指向整体申请的大小,remainbytes指向剩余字节数,freelist指向归还的头节点
先判断remainbytes是否比要申请的size小,如果小那么就重新申请内存大小,如果申请失败则抛异常。
申请成功则让memory转成obj的大小,取T个大小,判断一下T的size和void*的size哪个大,如果T的size小则取至少一个void*的大小,如果T的size大则取T的大小,方便后面链表的链接,objsize等于判断后的大小,让mem+obj=mem整个的剩余起始地址,remain的尺寸=remain-objsize
如果freelist中不等于空则优先调用freelist中的内存区域
首先先析构obj,再用链表将剩余的obj归还给freelist
freelist是个地址,取obj的头8位给freelist,然后再将freelist指针指向obj
测试代码
#ifndef CONCURRENTMEMORYPOOL_OBJECTPOOL_H
#define CONCURRENTMEMORYPOOL_OBJECTPOOL_H
#include <iostream>
#include<time.h>
#include<vector>
using std::cout;
using std::endl;
template<class T>
class ObjectPool{
public:
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*)malloc(_remainBytes);
if(_memory== nullptr) {
throw std::bad_alloc();//抛异常
exit(-1);
}
}
//走到这说明申请成功
obj=(T*)_memory;//强转成需要的大小
size_t objsize=sizeof(T)<sizeof (void*)?sizeof(void*):sizeof (T);
_memory+=objsize;//当前还剩余的空间
_remainBytes-=objsize;
}
//定位new,显示调用构造函数初始化,相当于在池子里开辟obj
new(obj)T;
return obj;
}
void Delete(T* obj){
// 显示调用析构函数清理对象
obj->~T();
*(void**)obj=_freeList;
_freeList=obj;
//不需要判断直接插入freelist
// if(_freeList== nullptr){
// _freeList=obj;
// *(void**)obj=nullptr;
// }
}
private:
char* _memory= nullptr;//char好切字节,指向大块内存的指针
size_t _remainBytes=0;//大块内存切分过程中的剩余字节数
void* _freeList= nullptr;//还回来过程中链接的自由链表的头指针
};
struct TreeNode
{
TreeNode()
:_val(0)
, _left(nullptr)
, _right(nullptr)
{
}
int _val;
TreeNode* _left;
TreeNode* _right;
};
void TestObjectPool()
{
// 申请释放的轮次
const size_t Rounds = 5;
// 每轮申请释放多少次
const size_t N = 100000;
std::vector<TreeNode*> v1;
v1.reserve(N);
size_t begin1 = clock();
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();
std::vector<TreeNode*> v2;
v2.reserve(N);
ObjectPool<TreeNode> TNPool;
size_t begin2 = clock();
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;
}