• c语言实现内存池


    概要

    所谓内存池,顾名思义和线程池的设计原理是一样的,为了减少频繁申请释放内存而带来的资源消耗,减少释放内存后产生的内存碎片。

    设计理念

    为了方便管理内存池的设计通常是划分出一定数量的内存块,这些内存块的长度是一样的; 用户申请内存块时返回空闲的内存块地址,如果内存块使用完毕就释放该内存块,将该内存块置为空闲状态,放回到内存池,供以后使用。

    内存池的设计核心几大模块:创建内存池,申请内存块,释放内存块,销毁内存池!

    当然这只是常用的内存池设计,实际项目中可以根据需求设计不同的线程池:内存块的长度不一,可以提供自定义的内存块设计等兼容性更高的内存池。

    本文只做内存池原理的讲解和实现最基础的内存池!更多的功能根据实际的需求进行扩展即可。

    内存池的设计思路有很多,可以给予链表,数组,队列等进行设计,核心就是怎么存储内存块信息;本期是基于链表进行的内存池设计。

    模块设计

    内存池结构

    内存块节点结构

    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;
    }
    复制代码

     

  • 相关阅读:
    Python单元测试
    聊聊动态线程池的9个场景
    蓝桥杯真题讲解:子矩阵(二维滑动窗口)
    Kotlin协程Flow浅析
    【黄啊码】MySQL入门—5、掌握这些数据筛选技能比你学python还有用-2
    postgresql-集合运算
    MongoDB安装及进程介绍
    安装包UI美化之路-进度条的多种配置方法
    (Ljava/lang/String;)Ljava/lang/Integer; @65: areturn
    多项式学习笔记
  • 原文地址:https://www.cnblogs.com/yhfs/p/18009559