HM 内存池设计(1)内存池设计

综合 参考了

a.C++ 应用程序性能优化,第 6 章:内存池
http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html

b.ARP内存池的设计。 http://www.cnblogs.com/bangerlee/archive/2011/09/01/2161437.html

1.MemBlock

typedef struct MemBlock
{
	uint32_t	index;//size
	uint32_t	nfree;//可用的最小内存单元数
	uint32_t	nfirst;//下一个最小可用内存单元编号
	struct MemBlock*	pNextBlock;//下一个index值相同的MemBlock
#ifdef MEM_ANALYSIS
	uint32_t	max_used;//达到的用到的chunk数目最大值
#endif
}MemBlock;
 

MemBlock 结构与a.的结构类似,index源自ARP中的index。一个memblock由MemBlock+nfree个chunk内存单元组成。

chunk的size为BOUNDARY_SIZE*(index+1)字节.每个chunk的头4个字节记录了所在的MemBlock的地址(如果没有pNextBlock可直接用index获得,或通过地址范围计算),

5-8个字节存放下一个可用的chunk的id.

之后又加入了struct MemBlock* pNextBlock;指针,当nfree为0或该index的memblock已没有可用chunk时,malloc一个新的memblock并挂在其后(单向链表).

2.memblok 的管理mempool

typedef struct MemPool
{

MemBlock *freeblock[MAX_INDEX];
char *pMemory;
}MemPool;

pMemory 指向所分配的一整块大内存池,freeblock[i]指向index为i的memblock.

 

源代码:

/*
 ============================================================================
 Name        : mempool.h
 Author      : mlj
 Version     : 0.1
 ============================================================================
 */

#ifndef MEMPOOL_
#define MEMPOOL_
#include <stdint.h>

#define MEM_ANALYSIS //统计memory的信息
#define  MAX_INDEX 20 
typedef struct MemBlock
{
	uint32_t	index;//size
	uint32_t	nfree;//可用的最小内存单元数
	uint32_t	nfirst;//下一个最小可用内存单元编号
	struct MemBlock*	pNextBlock;//下一个index值相同的MemBlock
#ifdef MEM_ANALYSIS
	uint32_t	max_used;//达到的用到的chunk数目最大值
#endif
}MemBlock;

typedef struct MemPool
{
	MemBlock *freeblock[MAX_INDEX];
	char *pMemory;
}MemPool;
#endif

 

/*
 ============================================================================
 Name        : mempool.c
 Author      : mlj
 Version     : 0.1
 ============================================================================
 */
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "mempool.h"

char max_free_chunk[MAX_INDEX]={
	0,10,10,10,10,
	10,10,10,10,10,
	0,0,0,0,0,
	0,0,0,0,0};

MemPool mypool;

#define BOUNDARY_INDEX 12
#define BOUNDARY_SIZE (1 << BOUNDARY_INDEX)

#define CHUNK_HEAD_SIZE ( sizeof(MemBlock*)+sizeof(uint32_t) ) 
#define CHUNK_DATA_SIZE(index)	( (size_t)BOUNDARY_SIZE*(index+1))  // 4096*(1<<19)  默认为int 类型,会越界
#define MEMBLOCK_SIZE(index)	( sizeof(MemBlock) + max_free_chunk[(index)]*( CHUNK_HEAD_SIZE + CHUNK_DATA_SIZE(index) ) )
 
#define APR_ALIGN(size, boundary)   (((size)+ ((boundary) - 1)) &~((boundary) - 1))


void MemBlock_init(MemBlock *block,uint32_t max_free_chunk)
{
	uint32_t i = 0;
	char *p = NULL;
	block->nfree = max_free_chunk;
	block->nfirst = 0;
	block->pNextBlock = NULL;
#ifdef MEM_ANALYSIS
	block->max_used = 0;
#endif
	p = (char*)block;
	((char*)p) += sizeof(MemBlock); //第0个chunk头地址
	for(i=0;i<block->nfree;i++)
	{
		( *((MemBlock**)p) ) = (MemBlock*)block; //chunk 头四个字节存放所在的MemBlock的地址
		((char*)p) += sizeof(MemBlock*);
		*((uint32_t*)p) = i+1; //5-8个字节存放下一个可用的chunk的index
		((char*)p) += sizeof(uint32_t)+CHUNK_DATA_SIZE(block->index);
	}
}

void MemPool_create(MemPool *pool)
{
	size_t pool_size = 0;//
	size_t i;
	char* p = NULL;
	for (i=0;i<MAX_INDEX;i++)
	{
		pool_size += MEMBLOCK_SIZE(i);
	}
	
	p = (char *)malloc(pool_size);
	if(p == NULL)
	{
		printf("memory malloc failed!/n");
		exit(0);
	}
	
	memset(p,0,pool_size);
	pool->pMemory = p;

	for (i=0;i<MAX_INDEX;i++)
	{
		pool->freeblock[i] = (MemBlock*) (p);
		pool->freeblock[i]->index = i;
		MemBlock_init(pool->freeblock[i],max_free_chunk[i]);
		((char*)p) += MEMBLOCK_SIZE(i);//注意转为char* 在加偏移
	}	
}

void MemPool_destroy(MemPool *pool)
{
	size_t i;
#ifdef MEM_ANALYSIS
	size_t pool_size = 0;//max_free_chunk[19] 不为0时,size_t的数据范围会不够
	for (i=0;i<MAX_INDEX;i++)
	{
		pool_size += MEMBLOCK_SIZE(i);
	}
	printf("MemPool analysis:\n");
	printf("Total malloc memory size:%dKB  %dM\n",pool_size>>10,pool_size>>20);
	printf("index   :");
	for (i=0;i<MAX_INDEX/2;i++)
	{
		printf("%4d",i);
	}
	printf("\nmax_used:");
	for (i=0;i<MAX_INDEX/2;i++)
	{
		MemBlock* pblock = NULL;
		uint32_t max_used = 0;
		pblock = mypool.freeblock[i];
		do 
		{
			max_used += pblock->max_used;
		}while (pblock=pblock->pNextBlock);
		printf("%4d",max_used);
	}
	printf("\nindex   :");
	for (i=MAX_INDEX/2;i<MAX_INDEX;i++)
	{
		printf("%4d",i);
	}
	printf("\nmax_used:");
	for (i=MAX_INDEX/2;i<MAX_INDEX;i++)
	{
		MemBlock* pblock = NULL;
		uint32_t max_used = 0;
		pblock = mypool.freeblock[i];
		do 
		{
			max_used += pblock->max_used;
		}while (pblock=pblock->pNextBlock);
		printf("%4d",max_used);
	}
#endif

	for (i=0;i<MAX_INDEX;i++)
	{
		MemBlock* pblock = NULL;
		pblock = mypool.freeblock[i];
		while (pblock->pNextBlock)
		{
			MemBlock* tmp = pblock->pNextBlock;
			pblock->pNextBlock = tmp->pNextBlock;
			free(tmp);
		}
	}
	free(pool->pMemory);
	pool->pMemory = NULL;
}

void* MemPool_malloc(size_t in_size)
{
	size_t size;
	size_t index;
    size = APR_ALIGN(in_size , BOUNDARY_SIZE);
    if (size < in_size) {
        return NULL;
    }
    if (size < BOUNDARY_SIZE)
        size = BOUNDARY_SIZE;

    /* Find the index for this node size by
     * dividing its size by the boundary size
     */
    index = (size >> BOUNDARY_INDEX) - 1;
    
    if (index > MAX_INDEX) {
        return NULL; //大于max_index的大小内存的处理
    }

	if (index<=MAX_INDEX)
	{
		MemBlock* pblock = NULL;
		pblock = mypool.freeblock[index];
		 //寻找block链表上第一个存在空闲chunk的block
		do 
		{
			if (pblock->nfree>0) //找到,退出
			{
				break;
			}
			else if (pblock->pNextBlock == NULL) //已满,下一memblock又不存在
			{
				char *p = NULL;
				if (max_free_chunk[index] == 0)
				{
					max_free_chunk[index] = 1;
				}
				
				p = (char*) malloc(MEMBLOCK_SIZE(index));
				if (p == NULL)
				{
					printf("memory malloc failed!/n");
					exit(0);
				}
				memset(p,0,MEMBLOCK_SIZE(index));				
				pblock->pNextBlock = (MemBlock*) (p);
				pblock->pNextBlock->index = index;
				pblock=pblock->pNextBlock;
				MemBlock_init(pblock,max_free_chunk[index]);
				break;
			}
			else
			{
				pblock=pblock->pNextBlock;
			}
		}while (pblock);
		
		
		if (pblock->nfree > 0)
		{
			uint32_t chunk_id = pblock->nfirst;//待分配的chunk的id
			char* pchunk = (char*)( pblock ) + sizeof(MemBlock)+ CHUNK_DATA_SIZE(index)*chunk_id;//第index个chunk的首地址
			pchunk = pchunk + sizeof(MemBlock*) ;//向后偏移四个字节,指向chunk id 区
			pblock->nfirst = *((uint32_t*)pchunk) ;//更新下一个可用chunk的id
			*((uint32_t*)pchunk) = chunk_id; //已分配出去的chunk,chunkid区记下自己的id
			pblock->nfree--;
#ifdef MEM_ANALYSIS
			{
				uint32_t used_chunk = max_free_chunk[index]-pblock->nfree;
				if (used_chunk>pblock->max_used)
				{
					pblock->max_used = used_chunk;
				}
			}
#endif
			return ( (char*)pchunk + sizeof(uint32_t) );
		}
		else
		{
			return NULL;
		}
	}
	return NULL;
}

void MemPool_free(void* _Memory)
{
	MemBlock *pblock = NULL;
	pblock = *( (MemBlock**)((char*)_Memory - CHUNK_HEAD_SIZE) ); //获取该chunk所在的block地址

	if (pblock->index <=MAX_INDEX)
	{//释放的chunk 挂到最前面,第一个可用的chunk
		uint32_t chunk_id = pblock->nfirst;
		char* poffset = ((char*)_Memory - sizeof(uint32_t)) ;//chunk_id地址
		pblock->nfirst =  * ( (uint32_t*)(poffset) );
		* ( (uint32_t*)(poffset) ) = chunk_id ;
		memset(_Memory,0,CHUNK_DATA_SIZE(pblock->index));//数据区置0 
	}
}

int main()
{
	char* p1[10];
	int i;
	MemPool_create(&mypool);
	for (i=0;i<6;i++)
	{
		p1[i]=(char*) MemPool_malloc(1024<<i);
	}
	for (i=0;i<6;i++)
	{
		MemPool_free(p1[i]);
		p1[i] = NULL;	
	}

	MemPool_destroy(&mypool);
}
posted @ 2012-06-07 15:50  mlj318  阅读(389)  评论(0编辑  收藏  举报