内存池的实现

内存池的实现

(Memory Pool)是一种内存分配方式,又被称为固定大小区块规划(fixed-size-blocks allocation)。通常我们习惯直接使用new、malloc等API申请分配内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能,同时调用库内的内存分配函数,十分耗时。

解决办法是使用内存池技术,小固定,提前申请,重复利用

因为内存的申请和释放是很低效的,所以我们只在开始时申请一块大的内存(在该块内存不够用时在二次分配),然后每次需要时都从这块内存中取出,并标记下这块内存被用了,释放时标记此内存被释放了。释放时,并不真的把内存释放给操作系统,只要在一大块内存都空闲的时候,才释放给操作系统。这样,就减少了new/delete的操作次数,从而提高了效率。在调用内存分配函数的时候,大部分时间所分配的内存大小都是一定的,所以可以采用每次都分配固定大小的内存块,这样就避免了内存碎片产生的可能。

下面是内存池的简单实现代码

#include "Allctor.h"
#include <memory>

struct tagMemoryBlock
{
	//链表处理
	class MemoryAlloc* alloc;//属于哪片内存块
	tagMemoryBlock* pNext;//下一片内存块
	bool bUse;//当前内存块是否被使用
	bool bPool;//当前内存块是否在内存池中
	int nID;
	char c[3];//进行对齐
};

class MemoryAlloc//内存片
{
private:
	unsigned int _nSize;
	unsigned int _nBlockSize;
	char* _pbuf;//存储开辟的内存
	tagMemoryBlock* _pHeader;
	int _nID;
public:
	MemoryAlloc(unsigned int nSize, unsigned int nBlockSize)//小片内存大小   块数
	{
		_nSize = nSize;
		_nBlockSize = nBlockSize;
		_nID = 1;
		_pbuf = (char*)malloc((nSize + sizeof(tagMemoryBlock)) * nBlockSize);
		_pHeader = (tagMemoryBlock*)_pbuf;
		_pHeader->alloc = this;
		_pHeader->nID = _nID++;
		_pHeader->pNext = nullptr;
		_pHeader->bPool = true;
		_pHeader->bUse = false;

		tagMemoryBlock* tmp = _pHeader;
		for (int i = 1; i < _nBlockSize; ++i)
		{
			tagMemoryBlock* block = (tagMemoryBlock*)(_pbuf + (nSize + sizeof(tagMemoryBlock)) * i);
			block->alloc = this;
			block->nID = _nID++;
			block->bUse = false;
			block->pNext = nullptr;



			block->bPool = true;
			tmp->pNext = block;
			tmp = block;//连接链表
		}
	}

	virtual ~MemoryAlloc()
	{
		free(_pbuf);
	}

	void* New(int nSize)
	{
		tagMemoryBlock* tmp = nullptr;
		if (_pHeader == nullptr)
		{
			tmp = (tagMemoryBlock*)malloc(nSize + sizeof(tagMemoryBlock));
			tmp->alloc = this;
			tmp->bPool = false;
			tmp->bUse = true;
			tmp->nID = 0;
			tmp->pNext = nullptr;
		}
		else
		{
			tmp = _pHeader;
			_pHeader = _pHeader->pNext;
			tmp->bUse = true;

		}
		printf("是否在内存池 %d  是否被使用 %d ID %d 内存大小 %d\n", tmp->bPool, tmp->bUse, tmp->nID,_nSize);
		return (tmp + 1);
	}

	void Delete(void* p)
	{
		tagMemoryBlock* tmp = ((tagMemoryBlock*)p - 1);
		printf("释放内存  是否在内存池 %d  是否被使用 %d ID %d 内存大小 %d\n", tmp->bPool, tmp->bUse, tmp->nID, _nSize);
		if (!tmp->bPool)
		{
			free(tmp);
			return;
		}
		tmp->bUse = false;
		tmp->pNext = _pHeader;
		_pHeader = tmp;//插入到头部
		
	}
};

template<int size, int blockSize>

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

class MemoryMgr//内存管理器
{
	MyMemoryAlloc<64, 1> _mem;
	MyMemoryAlloc<64, 100000> _mem64;
	MyMemoryAlloc<128, 100000> _mem128;
	MyMemoryAlloc<256, 100000> _mem256;
	MyMemoryAlloc<512, 100000> _mem512;
	MyMemoryAlloc<1024, 100000> _mem1024;

	MemoryAlloc* _szAlloc[1024];
public:
	MemoryMgr()
	{
		InitMem(0, 64, &_mem64);
		InitMem(65, 128, &_mem128);
		InitMem(129, 256, &_mem256);
		InitMem(257, 512, &_mem512);
		InitMem(513, 1024, &_mem1024);

	}
	//单例模式
	static MemoryMgr* Ins()
	{
		static MemoryMgr Mgr;
		return &Mgr;
	}



	void InitMem(int nBegin, int nEnd, MemoryAlloc* pMem)
	{
		for (int i = nBegin; i <= nEnd; ++i)
		{
			_szAlloc[i] = pMem;
		}
	}

	void* New(size_t size)
	{
		if (size <= 1024)
		{
			return _szAlloc[size]->New(size);
		}
		else
		{
			return _mem.New(size);
		}
	}

	void Delete(void* p)
	{
		tagMemoryBlock* tmp = ((tagMemoryBlock*)p - 1);
		tmp->alloc->Delete(p);
	}
};

void* operator new(size_t size)
{
	return MemoryMgr::Ins()->New(size);
}

void operator delete(void* p)
{
	MemoryMgr::Ins()->Delete(p);
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内存池是一种常见的内存管理技术,它可以在程序启动时预先分配一定数量的内存空间,并将其划分为多个固定大小的块,然后在程序运行过程中动态地将这些块分配给需要使用内存的对象,从而减少内存碎片和内存分配的时间开销。下面是一个简单的内存池实现示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define BLOCK_SIZE 1024 #define BLOCK_NUM 10 typedef struct _memory_block { void *start; void *end; struct _memory_block *next; } memory_block; typedef struct _memory_pool { size_t block_size; memory_block *free_list; memory_block *used_list; } memory_pool; memory_pool *memory_pool_create(size_t block_size) { memory_pool *pool = (memory_pool *) malloc(sizeof(memory_pool)); pool->block_size = block_size; pool->free_list = NULL; pool->used_list = NULL; for (int i = 0; i < BLOCK_NUM; i++) { memory_block *block = (memory_block *) malloc(sizeof(memory_block)); block->start = malloc(block_size); block->end = (char *) block->start + block_size; block->next = pool->free_list; pool->free_list = block; } return pool; } void *memory_pool_alloc(memory_pool *pool, size_t size) { memory_block *block = pool->free_list; while (block) { if ((char *) block->end - (char *) block->start >= size) { void *ptr = block->start; block->start = (char *) block->start + size; if (block->start == block->end) { pool->free_list = block->next; block->next = pool->used_list; pool->used_list = block; } return ptr; } block = block->next; } return NULL; } void memory_pool_free(memory_pool *pool) { memory_block *block = pool->used_list; while (block) { memory_block *next = block->next; free(block->start); free(block); block = next; } block = pool->free_list; while (block) { memory_block *next = block->next; free(block->start); free(block); block = next; } free(pool); } int main() { memory_pool *pool = memory_pool_create(BLOCK_SIZE); char *str1 = (char *) memory_pool_alloc(pool, 10); char *str2 = (char *) memory_pool_alloc(pool, 20); char *str3 = (char *) memory_pool_alloc(pool, 30); strcpy(str1, "hello"); strcpy(str2, "world"); strcpy(str3, "memory pool"); printf("%s %s %s\n", str1, str2, str3); memory_pool_free(pool); return 0; } ``` 该示例中,首先定义了两个结构体:memory_block表示内存块,包括起始地址、结束地址和下一个内存块的指针;memory_pool表示内存池,包括块大小、空闲链表和已用链表。 然后,定义了三个函数:memory_pool_create用于创建内存池,先分配一定数量的内存块,并将其加入空闲链表;memory_pool_alloc用于从内存池中分配一块指定大小的内存空间,遍历空闲链表,找到第一个大小足够的内存块,并将其划分为新的内存空间;memory_pool_free用于释放内存池中的所有内存块,将已用链表和空闲链表中的内存块全部释放。 最后,在main函数中创建一个内存池,并使用memory_pool_alloc从内存池中分配三个字符串空间,将其赋值并打印出来,最后使用memory_pool_free释放内存池中的所有内存块。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值