综合 参考了
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并挂在其后(单向链表).
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);
}