就给人写了个内存池

本文介绍了一个简单内存池的实现,用于不断创建和销毁对象。重载了new/delete,有alloc、dealloc、createpool三个基本接口。采用在内存块前加MemBlock管理,MemMgr管理MemPool的方式。还给出查询pool的方法,提醒多线程使用需加锁,对MemBlock管理给出思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写了一个简单的内存池; 主要用于需要不断的创建和销毁对象

已经重载了new/delete;

基本使用就3个接口

1. MemMgr::alloc  分配内存 (new 调用这个)

2.MemMgr::dealloc 释放 (delete调用这个)

3. MemMgr::createpool 创建内存池 ; 唯一需要额外调用的函数

基本思想就是在每个内存块前加一个MemBlock用于管理(用MemPool来管理),MemMgr来管理MemPool;

另外对于MemMgr来查询使用哪个pool 有多个方式,代码中给了2种方法;

我里面用map来管理pool , key用根据操作系统分配粒度的大小( sizeof(void*) ), 来找到最合适的pool,当然

前提是预先调用了createpool;

另外

1.下面的代码还没加锁, 需要用于多线程的可自行在 MemMgr 和 MemPool 中加锁;

2 . 还有对于MemBlock的管理方式并不是最好的一种, 只是给出一个思路, 可模拟目录对文件的管理方式;

 

1) MemBlock 每个申请的内存块都会附加这一头部

2) MemPool 可用于创建4字节, 8字节, 16字节.... 等等自定义的内存池. 最小的内存池还是以sizeof(void*)为单位 ,

    通过指定内存块大小和数量来malloc 后初始化所有内存块的首部(MemBlock), 内部还有一个pUserBlock 来记录

    哪些块已经使用;

3) MemMgr 用于管理MemPool , 查找并返回与字节数最匹配的内存池中的内存块, 当然还可以附加其他功能,

    额外的功能自行发挥好了

 

// mem_mgr.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>
#include <unordered_map>
#ifdef _DEBUG
	#define PR(...) printf(__VA_ARGS__)
#else
	#define  PR(...)
#endif



#define BLOCK_SIZE_4 4
#define BLOCK_SIZE_8 8
#define BLOCK_SIZE_16 16
#define BLOCK_SIZE_32 32
#define BLOCK_SIZE_64 64
#define BLOCK_SIZE_128 128
#define BLOCK_SIZE_256 256
#define BLOCK_SIZE_512 512
#define BLOCK_SIZE_1024 1024

class MemPool;
class MemMgr;
//内存块描述信息,附着在每个可用内存块的头部
struct MemBlock
{
	//index位置
	int id;
	//ref次数
	unsigned int nref;
	//属于哪个pool
	MemPool * pool;
	//下一个可使用地址 , 下面全部注释了, 这种方式不太好用
	MemBlock * next;
};

static void * new_from_system(size_t size){

	MemBlock *pRet = (MemBlock *)malloc(sizeof(MemBlock)+size);
	if (!pRet)
		return NULL;
	pRet->id = -1;
	pRet->next = 0;
	pRet->nref = 1;
	pRet->pool = 0;
	return ((char*)pRet) + sizeof(MemBlock);
}

//内存池
class MemPool
{
	//pool
	char *pBuffer;
	//可使用块单元,下面不再使用这个变量,用另一种查询方式
	MemBlock *pAviliableBlock;
	//MemBlock 大小
	unsigned  block_size;
	//MemBlock 数量
	unsigned  block_count;

	//内存块使用情况,用于查询
	char * pBlockUsed;
private:
	MemPool(const MemPool &);
	MemPool & operator = (const MemPool &);
public:
	MemPool(unsigned  blockSize, unsigned  blockCount) :
		pBuffer(0), pAviliableBlock(0), block_size(blockSize), block_count(blockCount),
		pBlockUsed(0){}
	~MemPool(){
		if (pBuffer){
			free(pBuffer);
		}
	}
	unsigned  blockSize() const { return block_size; }
	unsigned long long pool_size() const
	{
		return block_count * block_size;
	}
	int init(){
		if (pBuffer)
			return -1;
		unsigned block_total_len = block_size + sizeof(MemBlock);
		pBuffer = (char*)malloc(block_count * block_total_len);
		if (!pBuffer)
			return -1;
		pBlockUsed = (char*)malloc(block_count);
		if (!pBlockUsed)
			return -1;
		memset(pBlockUsed, 0, sizeof(char)*block_count);
		pAviliableBlock = (MemBlock *)pBuffer;
		MemBlock * p = NULL;
		for (unsigned i = 0; i < block_count; ++i){
			p = (MemBlock*)(pBuffer + i*block_total_len);
			p->id = i;
			//先写着
			p->next = (MemBlock*)(pBuffer + (i+1)*block_total_len);
			p->nref = 0;
			p->pool = this;
		}
		p->next = NULL;
		
		return 0;
	}
	void showEachBlock(){
		unsigned block_total_len = block_size + sizeof(MemBlock);
		for (unsigned i = 0; i < block_count; ++i){
			MemBlock * p = (MemBlock*)(pBuffer + i * block_total_len);
			printf("thisblock : %p , id:%d,nref:%d,next:%p \t", p, p->id, p->nref, p->next);
		}
		printf("\n");
	}
	void showUsedBlock(MemBlock * p = 0)
	{
		printf("\n *** alloc block blocksize : %ld , count:%ld ,pool:%p\t ", block_size, block_count, this);
		for (unsigned i = 0; i < block_count; ++i)
			printf("%d", pBlockUsed[i]);
		printf("\n");
		if (p){
			printf("thisblock : %p , id:%d,nref:%d,next:%p \t", p, p->id, p->nref, p->next);
		}
		printf("****\n");
	}
	void * alloc(size_t size) {
		if (!pBuffer)
			return NULL;
		MemBlock * pRet = NULL;
		unsigned i = 0;
		//找出可用内存块
		for (i = 0; i < block_count && 1 == pBlockUsed[i]; ++i);
		//超出内存池大小
		if (i == block_count){
			printf("pool is full  index:%d\n", i);
			return new_from_system(size);
		}
		else
		{
			pBlockUsed[i] = 1;
			pRet = (MemBlock *)(pBuffer + i*(block_size + sizeof(MemBlock)));
			pRet->nref = 1;
			showUsedBlock(pRet);
		}



		/*if (!pAviliableBlock){
		pRet = (MemBlock *)malloc(sizeof(MemBlock)+size);
		if (!pRet)
		return NULL;
		pRet->id = -1;
		pRet->next = 0;
		pRet->nref = 1;
		pRet->pool = 0;
		}
		else {
		pRet = pAviliableBlock;
		pAviliableBlock = pAviliableBlock->next;
		pRet->nref = 1;
		}*/
		return ((char*)pRet) + sizeof(MemBlock);
	}
	void deAlloc(void * pMem){
		if (!pMem){
			printf("empty pointer!  %s,%d\n", __FILE__, __LINE__);
			return;
		}
		MemBlock * pMemBlock = (MemBlock*)((char*)pMem - sizeof(MemBlock));
		if (!pMemBlock){
			printf("can't dealloc pMemBlock , %s,%d\n", __FILE__, __LINE__);
			return;
		}
		if (--pMemBlock->nref != 0){
			printf("memblock  nref:%d\n", pMemBlock->nref);
			return;
		}
		if (pMemBlock->pool){
			//这个情况在MemMgr中处理了, 不会发生
			if (pMemBlock->pool != this){
				printf("this block is not belong to this pool, this pool:%p, block_pool:%p  %d \n",
					this, pMemBlock->pool, __LINE__);
				return;
			}
			/*
			pMemBlock->next = pAviliableBlock;
			pAviliableBlock = pMemBlock;
			*/

			pBlockUsed[pMemBlock->id] = 0;
			showUsedBlock();
		}
		else{
			free(pMemBlock);
		}
	}
};

//管理, 默认最多创建20个内存池
class MemMgr
{
public:
	MemMgr(unsigned max_pool_count = 20) :_max_pool_count(max_pool_count),
		pBuffer(NULL), _cur_pool_count(0)
	{
		pBuffer = (char*)malloc(max_pool_count * sizeof(MemPool));
	}
	~MemMgr(){
		if (!pBuffer)
			return;
		MemPool * pStart = (MemPool *)pBuffer;
		for (unsigned i = 0; i < _cur_pool_count; ++i, pStart++)
			pStart->~MemPool();
		free(pBuffer);
		pBuffer = NULL;
	}
	static MemMgr& getInstance() {
		return _instance;
	}

	//申请内存,选择某一个池中的内存块
	//对于如何决定某个池中的内存块,有很多方式, 可自行决定如何去做
	void * alloc(size_t size){
		size_t blockSize = align_bytes(size);
		if (blockSize < 1){
			printf("blocksize error!  %d\n", __LINE__);
			return NULL;
		}
		//如果没有池就直接申请
		if (_pool_map.empty()){
			printf("_pool_map.empty! new from system  %d \n", __LINE__);
			return new_from_system(blockSize);
		}
		/*//	第一种方式, 以字节数为单位,作为key比如以4,8,16字节作为key, 找到对应的内存池
		auto iter = _pool_map.find(blockSize);
		if (iter == _pool_map.end()){
		printf("no such pool! %d\n", __LINE__);
		return new_from_system(blockSize);
		}
		else
		return iter->second->alloc(blockSize);
		*/

		//第2中方式,找到内存池中能容纳size的最小尺寸的池,这种方式灵活一些

		std::unordered_map<size_t, MemPool*>::iterator iter_find_min;
		for (iter_find_min = _pool_map.begin(); iter_find_min != _pool_map.end(); ++iter_find_min){
			if (size < iter_find_min->first)
				break;
		}
		if (iter_find_min == _pool_map.end()){
			printf("no such pool!  new from  system , pool size:%d ,  %d\n ",_pool_map.size(), __LINE__);
			return new_from_system(blockSize);
		}

		return iter_find_min->second->alloc(blockSize);

	}


	/*
		新建内存池,相同blocksize的池只能建立一个,你可自行改造一下成为多个池
	   以系统字节为边界 :sizeof(void*);
	   对于这个函数,即可以public,也可以private即自己预先分配好;
	  */
	int createPool(size_t blockSize = 8, size_t blockCount = 64)
	{
		if (!pBuffer){
			printf("%d failed , buffer malloc failed!\n", __LINE__);
			return -1;
		}
		if (_cur_pool_count >= _max_pool_count){
			printf("%d , max pool !\n", __LINE__);
			return -1;
		}
		if (blockSize < 1){
			printf("blocksize error!  %d\n", __LINE__);
			return -1;
		}
		blockSize = align_bytes(blockSize);
		//如果有相同尺寸的池,则不可新建
		if (_pool_map.find(blockSize) != _pool_map.end()){
			printf("key exists  blocksize:%ld, %d\n", blockSize, __LINE__);
			return -1;
		}
		MemPool *  pool = new(pBuffer + sizeof(MemPool)*_cur_pool_count)MemPool(blockSize, blockCount);
		if (pool->init() < 0){
			printf("pool init failed! %d\n", __LINE__);
			pool->~MemPool();
			return -1;
		}
		std::pair<std::unordered_map<size_t, MemPool*>::iterator, bool> insert_pair;
		insert_pair = _pool_map.insert(std::pair<size_t, MemPool*>(blockSize, pool));
		if (!insert_pair.second){
			printf("insert failed! %d\n", __LINE__);
			return -1;
		}
		++_cur_pool_count;
		return 0;
	}

	//释放
	void deAlloc(void * pMem){
		if (!pMem){
			printf("empty pointer!  %s,%d\n", __FILE__, __LINE__);
			return;
		}
		//也可以   (MemBlock*)pMem -1;
		MemBlock * pMemBlock = (MemBlock*)((char*)pMem - sizeof(MemBlock));
		if (!pMemBlock){
			printf("can't dealloc pMemBlock , %s,%d\n", __FILE__, __LINE__);
			return;
		}
		//如果在池中,交给池去处理
		if (pMemBlock->pool){
			pMemBlock->pool->deAlloc(pMem);
		}
		else {
			if (0 == --pMemBlock->nref){
				free(pMemBlock);
			}
		}
	}
	void addRef(void * p){
		MemBlock * pMemBlock = ((MemBlock*)p) - 1;
		++pMemBlock->nref;
	}
	//补齐字节使用,让字节数能被系统整除
	size_t align_bytes(size_t size){
		size_t bytes = sizeof(void*);
		return (size / bytes)*bytes + (size%bytes ? bytes : 0);
	}

private:
	MemMgr(const MemMgr&);
	MemMgr & operator = (const MemMgr&);
	static MemMgr _instance;
	unsigned _max_pool_count;
	unsigned _cur_pool_count;
	char * pBuffer;
	//第1,2种方式以补齐的字节数为单位作为key 的map
	std::unordered_map<size_t, MemPool*> _pool_map;
};
MemMgr MemMgr::_instance;

	
void * operator new (size_t size){
	return MemMgr::getInstance().alloc(size);
}
void operator delete(void * p){
	return MemMgr::getInstance().deAlloc(p);
}

void * operator new[](size_t size){
	return MemMgr::getInstance().alloc(size);
}
void operator delete[](void * p){
	return MemMgr::getInstance().deAlloc(p);
}
int _tmain(int argc, _TCHAR* argv[])
{
	MemMgr & instance = MemMgr::getInstance();
	instance.createPool(4, 5);
	
	/*char * p1 = new char;
	printf("p1:%p\n", p1);
	delete p1;
	p1 = new char[127];
	delete[] p1;*/

	char * arr[10];
	for (int i = 0; i < 10; ++i){
		arr[i] = new char[2];
	}
	for (int i = 0; i < 10; ++i){
		printf("arr[%d] = %p\t", i, arr[i]);
	}
	for (int i = 0; i < 10; ++i){
		delete[] arr[i];
	}

	getchar();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值