利用C/C++开发大型应用程序中,内存的管理与分配是一个需要认真考虑的部分。本文描述了内存池设计原理并给出内存池的实现代码,代码支持Windows和Linux,多线程安全。内存池设计过程中需要考虑好内存的分配与释放问题,其实也就是空间和时间的矛盾。有的内存池设计得很巧妙,内存分配与需求相当,但是会浪费过多的时间去查找分配与释放,这就得不偿失;实际使用中,我们更多的是关心内存分配的速度,而不是内存的使用效率。基于此,本文按照如下思想设计实现内存池。主要包含三个结构:StiaticMemory, MemoryChunk和MemoryBlock,三者之间的关系如下图所示:

1.内存的分配:
(1)如果分配大小超过1024,直接采用malloc分配,分配的时候多分配sizeof(size_t)字节,用于保存该块的大小;
(2)否则根据分配大小,查找到容纳该大小的最小size的MemoryChunk;
(3)查找MemoryChunk的链表指针pList,找到空闲的MemoryBlock返回;
(4)如果pList为NULL,临时创建MemoryBlock返回;
(5)MemoryBlock头部包含两个成员,pChunk指向的所属的MemoryChunk对象,size表明大小,其后才是给用户使用的空间;
2.内存的释放:
(1)根据释放的指针,查找器size头部,即减去sizeof(size_t)字节,判断该块的大小;
(2)如果大小超过1024,直接free;
(3)否则交给MemoryChunk处理,而块的头部保存了该指针,因此直接利用该指针就可以收回该内存。
注意的问题:
上述设计的内存池通过冗余的头部来实现内存块的分配与释放,减少了内存池的操作时间,速度上要优于原始的malloc和free操作,同时减少了内存碎片的增加。但是该设计中没有去验证释放的块冗余头部的正确性,因此故意释放不属于内存池中的块或者修改头部信息都会导致内存池操作失败,当然这些可以由程序员来控制。此外,内存池中分配出去的内存块如果不主动释放,内存池没有保留信息,不会自动释放,但是在退出的时候会验证验证是否完全释放,其实这个在系统测试时候就可以检测出来,我想这个缺陷也是可以弥补的,在此提出,希望使用者注意。
MemoryChunk.h 文件,线程安全
#ifndef MEMORY_CHUNK_H?
? ? #define MEMORY_CHUNK_H?
? ? #include ?
? ? #include ?
? ? #include ?
? ? ?
? ? #ifdef WIN32?
? ? #include ?
? ? typedef CRITICAL_SECTION MUTEXTYPE;?
? ? #define INITMUTEX(hMutex) InitializeCriticalSection(&hMutex)?
? ? #define DELMUTEX(hMutex) DeleteCriticalSection(&hMutex)?
? ? #define LOCK(hMutex) EnterCriticalSection(&hMutex)?
? ? #define UNLOCK(hMutex) LeaveCriticalSection(&hMutex)?
? ? #else?
? ? #include ?
? ? typedef pthread_mutex_t MUTEXTYPE;?
? ? #define INITMUTEX(hMutex) pthread_mutex_init(&hMutex,NULL)?
? ? #define DELMUTEX(hMutex) pthread_mutex_destroy(&hMutex)?
? ? #define LOCK(hMutex) pthread_mutex_lock(&hMutex)?
? ? #define UNLOCK(hMutex) pthread_mutex_unlock(&hMutex)?
? ? #endif?
? ? ?
? ? class MemoryChunk;?
? ? ?
? ? /** @struct MemoryBlock?
? ? *?
? ? */?
? ? struct BlockHeader?
? ? {?
? ? ? ? MemoryChunk* pChunk;?
? ? ? ? size_t len;?
? ? };?
? ? struct MemoryBlock;?
? ? struct BlockData?
? ? {?
? ? ? ? union{?
? ? ? ? ? ? MemoryBlock* pNext;?
? ? ? ? ? ? char pBuffer;?
? ? ? ? };?
? ? };?
? ? struct MemoryBlock?
? ? {?
? ? ? ? BlockHeader header;?
? ? ? ? BlockData data;?
? ? };?
? ? ?
? ? /** @class MemoryChunk?
? ? *?
? ? */?
? ? ?
? ? class MemoryChunk?
? ? {?
? ? public:?
? ? ? ? MemoryChunk(size_t size, int count)?
? ? ? ? {?
? ? ? ? ? ? INITMUTEX(hMutex);?
? ? ? ? ? ? this->pFreeList=NULL;?
? ? ? ? ? ? this->size=size;?
? ? ? ? ? ? this->count=0;?
? ? ? ? ? ? MemoryBlock* pBlock;?
? ? ? ? ? ? while(count--){?
? ? ? ? ? ? ? ? pBlock=CreateBlock();?
? ? ? ? ? ? ? ? if(!pBlock)break;?
? ? ? ? ? ? ? ? pBlock->data.pNext=pFreeList;?
? ? ? ? ? ? ? ? pFreeList=pBlock;?
? ? ? ? ? ? }?
? ? ? ? }?
? ? ? ? ~MemoryChunk()?
? ? ? ? {?
? ? ? ? ? ? int tempcount=0;?
? ? ? ? ? ? MemoryBlock* pBlock;?
? ? ? ? ? ? while(pBlock=pFreeList){?
? ? ? ? ? ? ? ? pFreeList=pBlock->data.pNext;?
? ? ? ? ? ? ? ? DeleteBlock(pBlock);?
? ? ? ? ? ? ? ? ++tempcount;?
? ? ? ? ? ? }?
? ? ? ? ? ? assert(tempcount==count);//!确保释放完全?
? ? ? ? ? ? DELMUTEX(hMutex);?
? ? ? ? }?
? ? ? ? void* malloc()?
? ? ? ? {?
? ? ? ? ? ? MemoryBlock* pBlock;?
? ? ? ? ? ? LOCK(hMutex);?
? ? ? ? ? ? if(pFreeList){?
? ? ? ? ? ? ? ? pBlock=pFreeList;?
? ? ? ? ? ? ? ? pFreeList=pBlock->data.pNext;?
? ? ? ? ? ? }?
? ? ? ? ? ? else{?
? ? ? ? ? ? ? ? if(!(pBlock=CreateBlock())){?
? ? ? ? ? ? ? ? ? ? UNLOCK(hMutex);?
? ? ? ? ? ? ? ? ? ? return NULL;?
? ? ? ? ? ? ? ? }?
? ? ? ? ? ? }?
? ? ? ? ? ? UNLOCK(hMutex);?
? ? ? ? ? ? return &pBlock->data.pBuffer;?
? ? ? ? }?
? ? ? ? static void free(void* pMem)?
? ? ? ? {?
? ? ? ? ? ? MemoryBlock* pBlock=(MemoryBlock*)((char*)pM