内存池C++实现

  程序在向系统申请内存时,很容易造成内存碎片,影响程序性能。内存池是一种内存分配策略,程序在之前,先向系统申请一大块内存,并将这一大块内存分割成若干小的内存块,供程序使用。当内存不足时再向系统申请。

  1、程序以1024位为界,将内存块block分为两种,一种是普通的block,可以直接向内存池申请,一种是大block,需要向系统申请;

  2、MemoryChunk中是一系列大小相等的block块,块的大小和数量都在初始化时给定,块的组织方式是链表结构,在分配或回收时需要考虑并发安全性;

  3、StaticMemory中是一系列大小MemoryChunk,这些Chunk的组织方向是数组形式,不同Chunk中,block的大小不等,向内存池申请内存时,会在合适大小的chunk中取出一块block返回给用户;




#ifndef MEMORY_CHUNK
#define MEMORY_CHUNK

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

struct MemoryBlock;

typedef struct BlockHeader{//头部
	MemoryBlock *next;
	size_t length;
}BlockHeader;

typedef struct BlockData{//数据
	char buffer;
}BlockData;

//Block的定义,本质上是一个链表结构
typedef struct MemoryBlock{
	BlockHeader header;//头部
	BlockData data;//数据部分
}MemoryBlock;

//Chunk是一系列Block的管理者
class MemoryChunk{//维护block及回收释放操作
public:
	//初始化里构建一定大小和数量的Block
	MemoryChunk(size_t size,size_t num)
	{
		pthread_mutex_init(&mutex,NULL);//互斥量初始化
		blockSize=size;//Block大小的初始化
		phead=NULL;//头指针
		MemoryBlock* pblock;
		blockNum=0;//Block块数大小的初始化,分配成功里再计数
		while(blockNum<num)
		{
			if((pblock=createBlock())!=NULL)
			{//分配成功,将Block加入到链表当中
				(pblock->header).next=phead;//下一指针
				(pblock->header).length=blockSize;//Block大小初始化
				phead=pblock;
				blockNum++;//Block块数增1
			}
			else
			{
				break;
			}
		}
	}

	~MemoryChunk()
	{
		MemoryBlock* pblock;
		while(phead)
		{
			pblock=phead;
			phead=(phead->header).next;
			::free(pblock);//将申请的内存归还给系统
			pblock=NULL;
			blockNum--;
		}
		assert(blockNum==0);//确保内存释放完全
		pthread_mutex_destroy(&mutex);
	}

	void* malloc()//分配内存
	{
		MemoryBlock* pBlock=NULL;
		pthread_mutex_lock(&mutex);
		if(phead)
		{//Chunk中有足够的Block,则直接分配
			pBlock=phead;
			phead=(phead->header).next;
			blockNum--;//总数量减1
		}
		else
		{//重新申请一块Block
			pBlock=createBlock();
		}
		pthread_mutex_unlock(&mutex);
		return &((pBlock->data).buffer);
	}

	void free(void* pmem)//回收内存
	{
		MemoryBlock* pblock;
		//对内存区域的操作,很重要
		pblock=(MemoryBlock*)((char*)pmem-sizeof(BlockHeader));
		free(pblock);
	}
	
	void free(MemoryBlock* pblock)
	{//回收到内存池当中
		pthread_mutex_lock(&mutex);
		(pblock->header).next=phead;
		phead=pblock;
		blockNum++;//Block问题增1
		pthread_mutex_unlock(&mutex);
	}

	size_t getBlockSize()//获取Chunk中block的大小
	{
		return blockSize;
	}

	size_t getBlockNum()//获取chunk中block的数量
	{
		return blockNum;
	}

protected:
	MemoryBlock* createBlock()//从系统当中获取内存
	{
		MemoryBlock* result;
		//sizeof返回的是字节数,blockSize存放的是位数
		result=(MemoryBlock*)::malloc(sizeof(BlockHeader)*8+blockSize);
		return result;
	}

private:
	MemoryBlock* phead;//头指针
	size_t blockSize;//Block大小
	size_t blockNum;//Block的数量
	pthread_mutex_t mutex;//互斥量
};

#endif //MEMORY_CHUNK


#ifndef STATICMEMORY
#define STATICMEMORY
#include"MemoryChunk.h"

typedef struct BigBlockHeader{
	size_t length;
}BigBlockHeader;

//大Block的结构
typedef struct BigBlock{
	BigBlockHeader header;
	char buffer;
}BigBlock;

//StaticMemory中存放的是不同大小的Chunk
class StaticMemory{
public:
	//Block的大小范围,最小为1字节
	enum{MAX_SIZE=1024,MIN_SIZE=8};

	StaticMemory()
	{
		count=0;//Chunk的数量
		for(size_t size=MIN_SIZE;size<MAX_SIZE;size*=2)
			++count;
		//构建Chunk的列表,内部都是指向Chunk的指针
		pChunkList=new MemoryChunk*[count];
		int index=0;
		for(size_t size=MIN_SIZE;size<MAX_SIZE;size*=2)
		{
			//每个Chunk中存放100个Block
			pChunkList[index++]=new MemoryChunk(size,100);
		}
	}

	~StaticMemory()
	{
		for(size_t index=0;index<count;++index)
		{//释放每一个Chunk指针,并调用其析构函数
			delete pChunkList[index];
		}
		delete [] pChunkList;
	}

	void *Malloc(size_t size)
	{
		if(size>MAX_SIZE)
		{//调用大Block的创建方法,大Block不在内存池内申请
			malloc(size);
		}
		else
		{
			int index=0;
			for(size_t tsize=MIN_SIZE;tsize<MAX_SIZE;tsize*=2)
			{//寻找合适大小的Block
				if(tsize>=size)
					break;
				index++;
			}
			return pChunkList[index]->malloc();//分配内存
		}
		return NULL;
	}

	void Free(void* pMem)
	{
		if(!free(pMem))
		{//如果不是大Block
			MemoryBlock* pblock;
			pblock=(MemoryBlock*)((char*)pMem-sizeof(BlockHeader));
			int index=0;
			for(size_t size=MIN_SIZE;size<MAX_SIZE;size*=2)
			{
				if((pblock->header).length==size)
					break;
				index++;
			}
			pChunkList[index]->free(pMem);
		}
	}

	size_t getCount()
	{
		return count;
	}
protected:

	void* malloc(size_t size)
	{	
		BigBlock* bblock;
		bblock=(BigBlock*)::malloc(sizeof(BigBlockHeader)*8+size);
		if(bblock)
		{
			(bblock->header).length=size;
			return &(bblock->buffer);
		}
		return NULL;
	}

	bool free(void* pMem)
	{//大Block的结构和普通block头部的结构有所区别,普通block前4字节
		//是一个指针,接下来4个字节是一个size_t类型变量
		//而大Block的头部中,只有一个size_t变量表示长度
		//所以两者头部长度是不等的,当为了判断一个block是否是大block
		//取长度时就应该注意指针的回退位置
		BigBlock* bblock;
		bblock=(BigBlock*)((char*)pMem-sizeof(BigBlockHeader));
		if((bblock->header).length>MAX_SIZE)
		{
			::free(bblock);
			return true;
		}
		return false;
	}

private:
	MemoryChunk** pChunkList;//Chunk列表
	size_t count;//不同大小的Chunk数量
};

#endif //STATICMEMORY


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值