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