概要
所谓内存池,顾名思义和线程池的设计原理是一样的,为了减少频繁申请释放内存而带来的资源消耗,减少释放内存后产生的内存碎片。
设计理念
为了方便管理内存池的设计通常是划分出一定数量的内存块,这些内存块的长度是一样的; 用户申请内存块时返回空闲的内存块地址,如果内存块使用完毕就释放该内存块,将该内存块置为空闲状态,放回到内存池,供以后使用。
内存池的设计核心几大模块:创建内存池,申请内存块,释放内存块,销毁内存池!
当然这只是常用的内存池设计,实际项目中可以根据需求设计不同的线程池:内存块的长度不一,可以提供自定义的内存块设计等兼容性更高的内存池。
本文只做内存池原理的讲解和实现最基础的内存池!更多的功能根据实际的需求进行扩展即可。
内存池的设计思路有很多,可以给予链表,数组,队列等进行设计,核心就是怎么存储内存块信息;本期是基于链表进行的内存池设计。
模块设计
内存池结构
内存块节点结构
- typedef struct MemoryBlock{
- void *data;//内存块起始地址
- struct MemoryBlock *next;//下一个内存块的地址
- }MemoryBlock;
内存池结构
- typedef struct MemoryPool{
- MemoryBlock *freeList;//空闲内存块链表
- MemoryBlock *usedList;//占用内存块链表
- int freeCount;//空闲内存块数量
- int usedCount;//占用内存块数量
- int blockCount;//内存块总数量
- }MemoryPool;
创建内存池
通过参数确定内存池中内存块的大小和数量,然后给每个内存块开辟空间,然后初始化空闲链表,占用链表,空闲数量,占用数量等
- MemoryPool *InitMemoryPool(int blockSize, int blockCount)
- {
- MemoryPool *pool = NULL;
- pool = (MemoryPool *)malloc(sizeof(MemoryPool));//为内存池分配空间
- pool->freeList = NULL;
- pool->usedList = NULL;
- for(int i = 0; i < blockCount; i++)
- {
- //创建内存块节点,插入到空闲链表
- MemoryBlock * block = (MemoryBlock *)malloc(sizeof(MemoryBlock));
- block->data = malloc(blockSize);
- block->next = pool->freeList;
- pool->freeList = block;
- }
- //初始化状态
- pool->freeCount = blockCount;
- pool->usedList = 0;
- pool->blockCount = blockCount;
- return pool;
- }
申请内存块
将内存池中空闲的内存块提供给用户使用,如果没有空闲内存块返回NULL。
- void *AllocateBlock(MemoryPool *pool)
- {
- if(pool->freeList == NULL || pool->freeCount == 0)
- return NULL;
- MemoryBlock *node = pool->freeList;
- //该内存块从空闲链表删除
- pool->freeList = node->next;
- //该内存块插入到占用链表
- node->next = pool->usedList;
- pool->usedList = node;
- //更新空闲,占用状态
- pool->usedCount++;
- pool->freeCount--;
- return node->data;
- }
释放内存块
将内存块放回到内存池
- void FreeBlock(MemoryPool *pool, void *data)
- {
- MemoryBlock *cur = pool->usedList;
- MemoryBlock *pre = NULL;
- //寻找给内存块的节点
- while(pre != NULL && cur->data != data)
- {
- pre = cur;
- cur = cur->next;
- }
- if(cur == NULL)
- return;
- //将该内存块从占用链表删除
- if(pre != NULL)
- pre->next = cur->next;
- else
- pool->usedList = cur->next;
- //将该内存块插入到空闲链表
- cur->next = pool->freeList;
- pool->freeList = cur;
- pool->freeCount++;
- pool->usedCount--;
- return;
- }
销毁内存池
销毁所有的内存块及分配过的空间
- void DestroyMemoryPool(MemoryPool *pool)
- {
- MemoryBlock *pre = NULL;
- //释放所有空闲内存块空间
- while(pool->freeList != NULL)
- {
- pre = pool->freeList;
- free(pool->freeList->data);
- pool->freeList = pool->freeList->next;
- free(pre);
- }
- //释放所有占用内存块空间
- while(pool->usedList != NULL)
- {
- pre = pool->usedList;
- free(pool->usedList->data);
- pool->usedList = pool->usedList->next;
- free(pre);
- }
- //释放内存池空间
- free(pool);
- pool->freeList = NULL;
- pool->usedList = NULL;
- pool->freeCount = 0;
- pool->usedCount = 0;
- return;
- }
至此一个最基础的内存池算是已经完成,在实际项目中可以在此基础上进行扩展;
main函数调用
- int main(void)
- {
- MemoryPool *pool;
- pool = InitMemoryPool(10, 5);
- int *str = (int *)AllocateBlock(pool);
- *str = 2;
- int *ptr = (int *)AllocateBlock(pool);
- *ptr = 3;
- printf("free block : %d, used block : %d\n", pool->freeCount, pool->usedCount);
- FreeBlock(pool, ptr);
- printf("free block : %d, used block : %d\n", pool->freeCount, pool->usedCount);
- DestroyMemoryPool(pool);
- return 0;
- }