在探讨内存池前,我们需要回顾一下池的相关知识!
池(pool):一组资源的集合。
这组资源在服务器启动之初就被完全创建好并初始化,这称为静态资源分配。当服务器进入正式运行阶段,即开始处理客户请求的时候,如果处理该请求需要相关的资源,就可以直接从池中获取,无需动态分配。
很显然,直接从池中取得所需资源比动态分配资源的速度要快很多,因为分配系统资源的系统调用都是很费时间的。当服务器处理完一个客户请求后,就可以把相关资源放回池中,无需执行系统调用来释放资源。
从最终的效果来看,池相当于服务器管理系统资源的应用层设施,它避免了服务器对内核的频繁访问。
根据不同的资源类型,池可以分为多种,常见的池有:内存池(划重点!!)、进程池、线程池、连接池。
我们在编写程序的过程中,经常要向系统申请内存空间,有时申请的多,有时申请的少,用完了之后又还给系统。当下次要申请空间时,又重复前面的操作。这样来来回回次数多了,不仅你烦了,内存也烦了,因为你频繁的申请空间、释放空间,导致产生了很多的内存碎片(这里的叫外碎片),而且这样的操作效率还不高。
【插播一条外碎片的知识:外碎片指的是还没有被分配出去(不属于任何进程),但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。外碎片是除了任何已分配区域或页面外部的空闲存储块。这些存储块的总和可以满足当前申请的长度要求,但是由于它们的地址不连续或其他原因,使得系统无法满足当前申请。】
那么,怎么才能提高分配内存的效率,以及减少外碎片呢?内存池同志挥手示意。
请内存池同志做下自我介绍。
内存池:大家好,我叫内存池,我是从系统上分配出来的一部分资源,简单来说,就是在需要使用内存之前,先向系统申请好大好大的一块内存,这块内存就由我来管理和分配。等我想使用内存的时候,我就在内存池里面分一块出来用;等这块内存用完了我就又把它放回内存池里,这样内存循环使用。当内存池里所有内存块都被使用的时候,就再申请一块更大的内存块作为新的内存池。由于是我来回收,无需系统调用来回收,这样分配内存的效率就高一些,也能减少外碎片的产生
【内存池是一种内存分配方式。内存池的优点是可以有效的减少内存碎片化,分配内存更加快速,减少内存泄漏等优点。】
用C++实现简单内存池,这里采用的结构是静态链表。如下图:
该内存池可以实现自主的内存管理机制:
1. 分配内存:alloc
(1)operator new
(2)构造
2. 回收内存:dealloc
(1)operator delete
(2)析构
C++ 实现内存池过程,附代码:
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](); //从系统开辟内存池
Node* pCur = pool;
// 构造内存池内部结构(静态链表)
for (pCur; pCur < pool + MEM_SIZE - 1; pCur = pCur + 1)
{
pCur->pnext = pCur + 1;
}
//将内存池最后一个内存块的pnext域指向NULL,当pool为NULL时,重新申请一块更大的内存
pCur->pnext = NULL;
}
//分配出去一个内存块使用
void* rt = pool;
pool = pool->pnext; //pool始终指向下一个可用内存块
return rt;
}
void dealloc(void* ptr) //回收内存
{
if (ptr == NULL)
{
return;
}
Node* pptr = (Node*)ptr; ///类型转换
pptr->pnext = pool; //将当前该内存块的pnext域指向pool
pool = pptr; //接着将当前该内存块的指针变为新的pool
}
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;
}