内存池是我们经常使用的一种池,常见的池还有进程池、线程池和连接池,今天我们就先讨论内存池。首先看一下池的定义
池:池就是在初始时,申请比刚开始要使用的资源大的多的资源空间,接下来使用时,直接从池中获取资源。
内存池:即在初始时申请分配一定数量的。大小相等的内存块留作备用,此后如有需要直接从该内存上进行分配,与传统的new、melloc申请空间相比,这种机制减少了频繁从内核中申请空间产生大量的内存空间碎片进而降低性能的现象。
内存池的实现核心有三步构造内存池的节点、申请内存池分配内存、释放内存并归还到内存池。
接下来我们先了解一个简单的内存池的构造,内存池实际上就是一个以链表形式进行管理的数组,有效的避免了数组删除、插入时数据的移动。
#include<iostream>
const int MEM_SIZE = 10;
template<typename T>
class MEM_Pool
{
public:
static MEM_Pool<T>* getInstance()
{
if (mmp == NULL)
{
mmp = new MEM_Pool<T>();
}
return mmp;
}
//申请空间
void* alloc(size_t size)
{
if (pool == NULL) //内存池为空(没有空闲的存储单元)
{
pool = (Node*)new char[(size + 4)*MEM_SIZE]();//size是对象的大小,4为pnext指针域的大小
Node* pCur = pool; //将内存池的最后一个指针域制NULL
for (pCur; pCur < pool + MEM_SIZE - 1; pCur = pCur + 1)
{
pCur->pnext = pCur + 1;
}
pCur->pnext = NULL;
}
void* rt = pool; //分配空间
pool = pool->pnext;//从空闲链表中去除已经分配的空间
return rt;
}
//释放空间,并将空间加入到内存池中
void dealloc(void* ptr)
{
if (ptr == NULL)
{
return;
}
Node* pptr = (Node*)ptr; //临时保存地址
pptr->pnext = pool;//加入到内存池
pool = pptr;//修改指向内存池的指针
}
private:
MEM_Pool()
{
pool = NULL;
}
MEM_Pool(const MEM_Pool<int>&);
class Node //内存池的个节点
{
public:
Node(T val = T()) :mdata(val), pnext(NULL){} //节点构造函数
public:
T mdata;
Node* pnext;
};
Node* pool;
static MEM_Pool<T>* mmp; // 实例化一个对象
};
template<typename T>
MEM_Pool<T>* MEM_Pool<T>::mmp = NULL;
class CGoods
{
public:
CGoods(std::string name, float price, int amount)
:mname(name), mprice(price), mamount(amount)
{}
void* operator new(size_t size)
{
return pmm->alloc(size);
}
void operator delete(void* ptr)
{
pmm->dealloc(ptr);
}
private:
std::string mname;
float mprice;
int mamount;
static MEM_Pool<CGoods>* pmm;
};
MEM_Pool<CGoods>* CGoods::pmm = MEM_Pool<CGoods>::getInstance();
int main()
{
CGoods* pgood1 = new CGoods("面包", 4.5, 100);
CGoods* pgood2 = new CGoods("矿泉水", 2.0,100);
delete pgood1;
return 0;
}