栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

内存池C++

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

内存池C++

内存池

首先一张图将一下内存池的原理
在C++中自己写内存池其实就是重载new delete和new[] delete[] 函数;为什么free和malloc不能重载呢?因为它俩是C语言提供的,C++基于C语言的所以是系统级函数。

  • 内存相当于一个大类,有一片内存供给内存片
  • 内存片就是分配内存的单位,根据分配大小单位大小也不同,有64字节,128字节等
  • 每一个内存片有一个头可以用于GC,标记这片内存的大小以及使用情况
  • 内存的分配方式 单位内存*分配数量
流程如下:


这里内存管理器是单例模式,所以一开始不同单位的内存池就会加载好。
下面上代码:
每块内存片的头:

//头  =>用于GC和其他
struct tagMemoryBlock
{
	class MemoryAlloc* alloc;//属于那片内存
	tagMemoryBlock* pNext;//下一个内存块
	int nId; //测试编号
	bool bUse; //是否使用
	bool bPool;//是否在内存池中
	char c[2]; //16字节对齐    寄存器移位
	//按照最大数据类型对齐
};

内存片:

//内存片
class MemoryAlloc
{
private:
	unsigned int _nSize; //单位内存 
	unsigned int _nBlockSize; //数量   
	char* _pBuff;//存储开辟的内存
	tagMemoryBlock* _pHead;
	int _nId;
public:
	MemoryAlloc(unsigned int nSize, unsigned int nBlockSize)
	{
		_nSize = nSize;
		_nBlockSize = nBlockSize;
		_nId = 1;
		_pBuff = (char*)malloc((_nSize + sizeof(tagMemoryBlock)) * _nBlockSize);
		_pHead = (tagMemoryBlock*)(_pBuff);
		_pHead->alloc = this;
		_pHead->nId = _nId++;
		_pHead->pNext = nullptr;
		_pHead->bUse = false;//默认没有被使用
		_pHead->bPool = true;  //默认在内存池中间

		tagMemoryBlock* temp = _pHead;

		for (unsigned i = 1; i < _nBlockSize; i++)
		{
			tagMemoryBlock* block = (tagMemoryBlock*)(_pBuff + (_nSize + sizeof(tagMemoryBlock)) * i);
			block->alloc = this;
			block->nId = _nId++;
			block->pNext = nullptr;

			block->bUse = false;
			block->bPool = true;

			temp->pNext = block;
			temp = block;
		}
	}
	//用虚析构函数是为了解决继承的子类析构的时候的问题
	virtual ~MemoryAlloc()
	{
		free(_pBuff);
	}


	//申请内存  分配内存
	void* NewMemory(int nSize)
	{
		tagMemoryBlock* temp = nullptr;
		if (_pHead == nullptr)
		{
			//如果不在这片内存池中 手动new一个
			temp = (tagMemoryBlock*)malloc(((nSize)+sizeof(tagMemoryBlock)));
			temp->bPool = false;
			temp->bUse = true;
			temp->alloc = this;
			temp->pNext = nullptr;
			temp->nId = 0;//表示 不存在手动分配的

		}
		else
		{
			temp = _pHead;
			_pHead = _pHead->pNext;
			temp->bUse = true;
		}
		printf(" 申请内存:是否在内存池 : %d   是否使用 : %d   ID : %d  内存大小 : %dn", temp->bPool, temp->bUse, temp->nId, _nSize);

		return (temp + 1);
	}


	void DeleteMemory(void* p)
	{
		tagMemoryBlock* temp = (((tagMemoryBlock*)p) - 1);
		printf(" 释放内存:是否在内存池 : %d   是否使用 : %d   ID : %d  内存大小 : %dn", temp->bPool, temp->bUse, temp->nId, _nSize);
		if (!temp->bPool)
		{
			free(temp);
			return;
		}

		temp->bUse = false;
		temp->pNext = _pHead;
		_pHead = temp;

	}

};

内存管理器:

//内存管理器
class MemoryMgr
{
	TestMemoryAlloc<64, 1>_mem;
	TestMemoryAlloc<64, 100000>_mem64;
	TestMemoryAlloc<128, 100000>_mem128;
	TestMemoryAlloc<256, 100000>_mem256;
	TestMemoryAlloc<512, 100000>_mem512;
	TestMemoryAlloc<1024, 100000>_mem1024;
	MemoryAlloc* _szAlloc[1025];
public:
	static MemoryMgr* Ins()
	{
		static MemoryMgr ins;
		return &ins;
	}

	MemoryMgr()
	{
		InitMem(0, 64, &_mem64);
		InitMem(65, 128, &_mem128);
		InitMem(129, 256, &_mem256);
		InitMem(257, 512, &_mem512);
		InitMem(513, 1024, &_mem1024);
	}
//初始化对应内存池
	void InitMem(int nBegin, int nEnd, MemoryAlloc* pMem)
	{
		for (int i = nBegin; i <= nEnd; i++)
		{
			_szAlloc[i] = pMem;
		}
	}
//内存池的new方法
	void* New(size_t nSize)
	{
		if (nSize <= 1024)
		{
			std::cout << "11111" << std::endl;
			return _szAlloc[nSize]->NewMemory(nSize);
		}
		else
		{
			std::cout << "00000" << std::endl;;
			return _mem.NewMemory(nSize);
		}
	}
//内存池的delete方法
	void Delete(void* p)
	{
		tagMemoryBlock* temp = (((tagMemoryBlock*)p) - 1);
		temp->alloc->DeleteMemory(p);
	}

};

为什么不把MemoryAlloc改成模板呢?因为不好用…所以继承一下再改子类
然后把这个写成模板 为了解决tagMemory结构体没有指定大小而无法直接使用所以使用模板

模板

template 

class TestMemoryAlloc :public MemoryAlloc
{
public:
	TestMemoryAlloc() :MemoryAlloc(size, blockSize) {}
};

然后就是重载new new[] delete delete[] 方法;
最后附上代码一份!
如有错误还请指正!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/429752.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号