内存池

一、内存池的概念
  内存池是一种内存分配方式。通常我们习惯直接使用new、malloc等接口申请内存,这样做的缺点在于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。

  内存池则是在真正使用内存之前,预先申请分配一定数量、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。

二、内存池的流程和设计
1. 先申请一块连续的内存空间,该段内存空间能够容纳一定数量的对象。

2. 每个对象连同一个指向下一个对象的指针一起构成一个内存节点(Memory Node)。各个空闲的内存节点通过指针形成一个链表,链表的每一个内存节点都是一块可供分配的内存空间。

3. 某个内存节点一旦分配出去,从空闲内存节点链表中去除。

4. 一旦释放了某个内存节点的空间,又将该节点重新加入空闲内存节点链表。

5. 如果一个内存块的所有内存节点分配完毕,若程序继续申请新的对象空间,则会再次申请一个内存块来容纳新的对象。新申请的内存块会加入内存块链表中。

#include <iostream>
using namespace std;

template<int ObjectSize, int NumofObjects = 20>
class MemPool
{
private:
	//空闲节点结构体
	struct FreeNode
	{
		FreeNode* pNext;
		char data[ObjectSize];
	};

	//内存块结构体
	struct MemBlock
	{
		MemBlock* pNext;
		FreeNode data[NumofObjects];
	};

	FreeNode* freeNodeHeader;
	MemBlock* memBlockHeader;

public:
	MemPool()
	{
		freeNodeHeader = NULL;
		memBlockHeader = NULL;
	}

	~MemPool()
	{
		MemBlock* ptr;
		while (memBlockHeader)
		{
			ptr = memBlockHeader->pNext;
			delete memBlockHeader;
			memBlockHeader = ptr;
		}
	}
	void* malloc();
	void free(void*);
};

//分配空闲的节点
template<int ObjectSize, int NumofObjects>
void* MemPool<ObjectSize, NumofObjects>::malloc()
{
	//无空闲节点,申请新内存块
	if (freeNodeHeader == NULL)
	{
		MemBlock* newBlock = new MemBlock;
		newBlock->pNext = NULL;

		freeNodeHeader=&newBlock->data[0];	 //设置内存块的第一个节点为空闲节点链表的首节点
		//将内存块的其它节点串起来
		for (int i = 1; i < NumofObjects; ++i)
		{
			newBlock->data[i - 1].pNext = &newBlock->data[i];
		}
		newBlock->data[NumofObjects - 1].pNext=NULL;

		//首次申请内存块
		if (memBlockHeader == NULL)
		{
			memBlockHeader = newBlock;
		}
		else
		{
			//将新内存块加入到内存块链表
			newBlock->pNext = memBlockHeader;
			memBlockHeader = newBlock;
		}
	}
	//返回空节点闲链表的第一个节点
	void* freeNode = freeNodeHeader;
	freeNodeHeader = freeNodeHeader->pNext;
	return freeNode;
}

//释放已经分配的节点
template<int ObjectSize, int NumofObjects>
void MemPool<ObjectSize, NumofObjects>::free(void* p)
{
	FreeNode* pNode = (FreeNode*)p;
	pNode->pNext = freeNodeHeader;	//将释放的节点插入空闲节点头部
	freeNodeHeader = pNode;
}

class ActualClass
{
	static int count;
	int No;

public:
	ActualClass()
	{
		No = count;
		count++;
	}

	void print()
	{
		cout << this << ": ";
		cout << "the " << No << "th object" << endl;
	}

	void* operator new(size_t size);
	void operator delete(void* p);
};

//定义内存池对象
MemPool<sizeof(ActualClass), 2> mp;

void* ActualClass::operator new(size_t size)
{
	return mp.malloc();
}

void ActualClass::operator delete(void* p)
{
	mp.free(p);
}

int ActualClass::count = 0;

int main()
{
	ActualClass* p1 = new ActualClass;
	p1->print();

	ActualClass* p2 = new ActualClass;
	p2->print();
	delete p1;

	p1 = new ActualClass;
	p1->print();

	ActualClass* p3 = new ActualClass;
	p3->print();

	delete p1;
	delete p2;
	delete p3;
}

第二种写法 采用静态链表

const int MEM_SIZE = 10;
template<typename T>
class MEM_Pool
{
public:
	static MEM_Pool<T>* getInstance()
	{
		if (psing == NULL)
		{
			psing = new MEM_Pool<T>();
		}
		return psing;
	}
	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;
			}
			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<T>&);
	class Node
	{
	public:
		Node(T val = T()) :mdata(val), pnext(NULL){}
	public:
		T mdata;
		Node* pnext;
	};
	Node* pool;
	static MEM_Pool<T>* psing; 
};
template<typename T>
MEM_Pool<T>* MEM_Pool<T>::psing = NULL;
class CGoods
{
public:
	CGoods(const 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);
	}
	void print()
	{
		cout<<this<<": "<<endl;
	}
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, 200);
	pgood1->print();
	CGoods* pgood2 = new CGoods("香肠", 2.0, 100);
	pgood2->print();
	CGoods* pgood3 = new CGoods("面包", 4.5, 200);
	pgood3->print();
	CGoods* pgood4 = new CGoods("香肠", 2.0, 100);
	pgood4->print();
	CGoods* pgood5 = new CGoods("面包", 4.5, 200);
	pgood5->print();
	delete pgood1;
	CGoods* pgood6 = new CGoods("香肠", 2.0, 100);
	pgood6->print();

	
	delete pgood2;
	delete pgood3;
	delete pgood4;
	delete pgood5;
	delete pgood6;
	return 0;
}

内存池的特点:

  • 针对特殊情况,例如需要频繁分配释放固定大小的内存对象时,不需要复杂的分配算法和多线程保护。也不需要维护内存空闲表的额外开销,从而获得较高的性能。
  • 由于开辟一定数量的连续内存空间作为内存池块,因而一定程度上提高了程序局部性,提升了程序性能。
  • 比较容易控制页边界对齐和内存字节对齐,没有内存碎片的问题。
  • 当需要分配管理的内存在100M一下的时候,采用内存池会节省大量的时间,否则会耗费更多的时间。
  • 内存池可以防止更多的内存碎片的产生。
  • 更方便于管理内存。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值