图解内存分配算法 -- 内存池管理算法

图解内存分配算法 – 内存池管理算法

1. 算法介绍

内存池算法也是内存分配算法中相对较为常见的一种,其根本思想是将一跨大内存分割成许多份大小相同的小内存块,各小内存块通过链表或列表链接在一起,操作时每次申请释放一块小内存块。

由于一个大内存块只支持一种大小类型的小内存块,通常在使用时为了满足设计需求,可以通过创建多个内存池的方式,每个内存池下分割的内存块大小不一样,从而实现不同大小的内存块分配方案。

此内存分配算法源码参考自: <rt-thread mempool>

2. 算法图解

2.1 约定

为了方便大家阅读,以及本博客编写,对以下名称进行约定,以下约定适用于本篇博文所有内容:

  • 内存池:一大块连续的内存,其内可以拆分成多个小内存块

  • 内存块:一小块连续的内存,很多块内存块构成一个内存池,可以理解为内存池内的一个子单元。(包含内存块头和有效内存空间)

2.2 数据结构

管理整个内存池有一个重要数据结构,但其存储位置不位于内存池中!而是在内存池外的其他内存区域(如系统堆),其数据结构体如下:

struct rt_mempool
{
    struct rt_object parent;                            /**< inherit from rt_object */

    void            *start_address;                     /**< memory pool start */
    rt_size_t        size;                              /**< size of memory pool */

    rt_size_t        block_size;                        /**< size of memory blocks */
    rt_uint8_t      *block_list;                        /**< memory blocks list */

    rt_size_t        block_total_count;                 /**< numbers of memory block */
    rt_size_t        block_free_count;                  /**< numbers of free memory block */

    rt_list_t        suspend_thread;                    /**< threads pended on this resource */
};

我们重点关注其中最为重要的以下几个参数即可:

  • start_address: 内存池起始地址
  • size: 内存池大小
  • block_size: 内存块的大小
  • block_list: 内存块列表,类似于链表,其上面挂载着所有空闲的内存块
  • block_total_count: 内存池中内存块的总个数
  • block_free_count: 内存池中空闲内存块的个数

在这里插入图片描述

2.3 初始化

在这里插入图片描述

内存池初始化,其主要是将一整块完整的内存,分割成大小相同的很多块内存块,每块内存块前配备由一个头部;当然另外一种处理办法是根据需要的内存块数量以及每块内存块的大小,计算出整个内存池的大小,之后动态申请一块这么大的内存用于内存池管理。

每个内存块前面有一个内存块头,此内存块头为一个指针大小(32位mcu内为4字节),其内存储了下一个内存块的内存块头的地址。初始化的时候,内存池的各个内存块通过此内存块头进行单向链接,构成一个列表,第一个内存块的地址存储在内存池控制块的 block_list 字段内,而最后一个内存块的内存块头存储内容为 NULL 空,代表结束。

Pass: 注意此内存块头不会占用malloc申请的有效数据空间,而是在这块内存空间的前面!
在这里插入图片描述

2.4 第一次内存申请 malloc

在这里插入图片描述

对于内存池的内存申请的操作如下:

  1. 判断申请的内存大小是否小于等于一个内存块的有效内存大小,如果大于则申请失败

  2. 根据内存池控制块的 block_list 成员找到第一个内存块

  3. 修改内存池控制 block_list 成员的值,之前存放的是第一个空闲内存块的内存块头的地址,现在第一个内存块被分配出去了,因此需要修改其为第二个内存块的内存块头地址

  4. 修改此内存块的内存块头,此内存块头在没有分配出去之前,其存放的是下一个空闲内存块的内存块头地址,现在需要修改它为内存池控制块的地址,以方便后续对此内存进行回收

2.5 第二次内存申请 malloc

在这里插入图片描述

第二次内存申请操作于第一次内存申请操作一致,后续内存申请也是如此进行。

2.6 内存释放 free

在这里插入图片描述

内存释放则是需要将此内存块继续添加到内存池控制块所管理的空闲内存块列表中。

在将此内存分配出去之前,我们有一个重要操作得以帮助我们能将此内存成功回收回来,那便是在将此内存分配出去之前,我们将对应内存池控制块的地址信息存入了此内存块的内存块头!通过 free 传入的参数减掉一个指针大小即可将其对应内存池控制块的地址提取出来。

获取到对应内存池控制块之后,修改此内存块的内存块头内容为内存池控制块 block_list 的内容,之后再修改内存池控制块的 block_list 内容修改为当前内存块头的地址,这样就成功的将此内存块又插入到了内存池的空闲内存块列表中了,也就完成了当前内存块的释放操作了!

3. 总结

🆗,以上便是内存池管理算法的完整实现图解了!理解清楚了之后不妨思考一下此算法的优缺点是什么,欢迎大家将各自的思考在评论区进行交流讨论!也建议大家对其源码进行阅读,有了这份指南再去阅读源码 <rt-thread mempool>,相信会吃的更加透彻!


创作不易,转载请注明出处!

关注、点赞+收藏,可快速查收博主有关分享!


如果你觉得我文章写的不错,欢迎点赞、关注+收藏,谢谢~,以下我的一些推荐:


相关推荐:

  • 21
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱出名的狗腿子

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值