小内存使用内存池管理策略及实例

近期在使用做OSIP做项目开发时,发现其中使用了过多的小内存的申请,大的也就几百个字节,小的也就三五个字节,这些字节的申请对于系统内存本身就是一个负担。

为此想使用内存池进行代替。方法很简单,在不改变现在的内存分配方式,不修改过多的文件,弄一个简单的内存池分配方法。

在看了好多人写的后,采用了其中一个兄弟的内存分配想法。加上自己的调整。花了一天时间,搞了一个版本出来。

至少在目前进行30万次通话时,没有发现什么异常。我就把草稿代码贴出来,可以使用的,一起分享。


#include <stdio.h>
#include <malloc.h>
#include <string.h>

typedef struct _point_type {
	void *point;
	char *data;
}PointType;

typedef struct _memory_block
{
	struct _memory_block *pNext; //下一个内存单元
	struct _memory_block *pPrev; //上一个内存单元
	size_t	flag;//标识当前Block的使用的字节最大范围。使用0x00000000进行掩码区别。目前主要对小于1KByte的进行内存池管理.
	char* data; //数据,
} MemoryBlock;

typedef struct _memory_pool
{
	unsigned int blockCount;//申请块数量
	unsigned int blockCountStep;//内存块数增长步长
	unsigned int blockSize;//单个块的大小
	unsigned int freeCount;//空闲的内存块数
	MemoryBlock *freeHead; //空闲的头
	MemoryBlock *freeTail; //空闲的尾
	MemoryBlock *usedHead; //已使用的头
	MemoryBlock *usedTail; //已使用的尾
	char *pBlockMemoryHead; //块的头指针,用于释放内存时候用(因为块的分配了一大块的内存)
	char *pDataMemoryHead;//数据区域头指针
} MemoryPool;

int Xpool_init(unsigned int blockCount, unsigned int blockSize);
int Xpool_destroy(void);
void* Xpool_alloc(unsigned int size);
int Xpool_free(void *ptr);

static int Xpool_block(unsigned int blockCount, unsigned int blockSize);
static MemoryPool memory;

//初始化内存池
int Xpool_init(unsigned int blockCount, unsigned int blockSize)
{
	MemoryPool *p = &memory;
	p->blockCount = blockCount;
	p->blockSize = blockSize;
	p->freeCount = blockCount;
	p->blockCountStep = 100;
	p->freeHead = p->freeTail = NULL;
	p->usedHead = p->usedTail = NULL;

	Xpool_block(blockCount, blockSize);
	return 0;
}

//申请块,并且把新申请的块连到空闲块后面
static int Xpool_block(unsigned int blockCount, unsigned int blockSize)
{
	MemoryPool *p = &memory;
	MemoryBlock *pFree = NULL;//空闲块连表指针

	p->pBlockMemoryHead = (char *)malloc(sizeof(MemoryBlock) * blockCount);//分配一大块连续的内存块空间存放块信息
	p->pDataMemoryHead = (char *)malloc((blockSize + sizeof(MemoryBlock *)) * blockCount);//分配一大块连续的内存空间存放供用户使用的空间

	for (unsigned int i = 0; i < blockCount; i++)
	{
		pFree = (MemoryBlock *)(p->pBlockMemoryHead + (sizeof(MemoryBlock) * i));//(MemoryBlock *)malloc(sizeof(MemoryBlock));
		pFree->data = p->pDataMemoryHead + ((blockSize + sizeof(MemoryBlock *)) * i);//(void *)malloc(blockSize + sizeof(MemoryBlock *));//分配一块数据区域
		pFree->pNext = NULL;
		pFree->pPrev = p->freeTail;

		if (p->freeHead == NULL) {
			p->freeHead = p->freeTail = pFree;
		}
		else {
			p->freeTail->pNext = pFree;
			p->freeTail = pFree;
		}
	}

	return 0;
}

//销毁内存池
int Xpool_destroy(void)
{
	MemoryPool *p = &memory;

	//释放内存块所占的内存
	free(p->pBlockMemoryHead);

	//释放数据区域所占的内存
	free(p->pDataMemoryHead);

	return 0;
}

//申请内存
void* Xpool_alloc(unsigned int size)
{
	MemoryPool *p = &memory;
	MemoryBlock *block = NULL;

	if (p->freeHead == NULL) {//没有可用空间
		Xpool_block(p->blockCountStep, p->blockSize);
	}

	block = p->freeHead;//获取表头内存块
	p->freeHead = block->pNext;//将空闲块的链表头
	p->freeCount--;//空闲块数量减一
	block->pNext = NULL;
	block->pPrev = p->usedTail;//这个块的上个块是已使用块的最后一个块

	//第一次使用内存?
	if (p->usedHead == NULL) {
		p->usedHead = p->usedTail = block;//,则已使用的头和尾都指向这个块
	}
	else {//不是第一次
		p->usedTail->pNext = block;
		p->usedTail = block;
	}
	//留下data里一个指针的空间,用于保存与数据关联的块地址
#if 0
	char *ptr = (char *)block->data;// +sizeof(MemoryBlock *);
	*(double*)ptr = *(double*)&block;
	return ptr+ sizeof(MemoryBlock *);// (char *)block->data + sizeof(MemoryBlock *);
#else
	PointType *pt = (PointType*)block->data;
	pt->point = (void*)block;
	//pt->data = (char *)block->data + sizeof(MemoryBlock *);
	return (char *)block->data + sizeof(MemoryBlock *);// pt->data;


#endif
}

//回收内存
int Xpool_free(void *ptr)
{
	MemoryPool *p = &memory;

	

	PointType* pPT = (PointType*)((char*)ptr - ((unsigned long)(&((PointType*)0)->data)));

	//char *realptr = (char *)ptr - sizeof(MemoryBlock *); //数据块真实的起始地址
	MemoryBlock *block = (MemoryBlock*)pPT->point;
	//*(double*)&block = *(double *)realptr;


	if (block == NULL) {
		return NULL;
	}

	if (block->pPrev == NULL) {//如果是头
		p->usedHead = block->pNext;
		if (p->usedHead != NULL) {
			p->usedHead->pPrev = NULL;
		}
	}
	else if (block->pNext == NULL) {//如果是尾
		p->usedTail = block->pPrev;
		if (p->usedTail != NULL) {
			p->usedTail->pNext = NULL;
		}
	}
	else {//中间的
		block->pPrev->pNext = block->pNext;
		block->pNext->pPrev = block->pPrev;
	}

	//重置参数
	block->pPrev = p->freeTail;
	block->pNext = NULL;
	block->data = (char*)pPT;

	//加到空闲块链表
	p->freeTail->pNext = block;
	p->freeTail = block;
	p->freeCount++;

	return 0;
}

int main(int argc, char *argv[])
{
	char *p;
	Xpool_init(100, 128);
	for (int i = 0; i < 2; i++)
	{

	p = (char *)Xpool_alloc(20);
	printf("%p\n", p);
	}
	Xpool_free(p);
	Xpool_destroy();
	return 0;
}

其中的flag是我后来加入的,代码中也写我的个人想法。

对于之前兄弟写的部分,我做了些调整,有兴趣可以找一下比较。本想弄一个C++的版本。看是否有时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值