图解内存分配算法 -- 小内存分配算法

news2024/9/22 17:22:07

图解内存分配算法 – 小内存分配算法

文章目录

  • 图解内存分配算法 -- 小内存分配算法
    • 1. 算法介绍
    • 2. 算法图解
      • 2.1 约定
      • 2.2 数据结构介绍
      • 2.3 初始化
      • 2.4 第一次 malloc 40字节
      • 2.5 第二次 malloc 18 字节
      • 2.6 第三次 malloc 20字节
      • 2.7 第四次 malloc 40字节
      • 2.8 第一次 free
      • 2.9 第二次 free 内存合并处理碎片
    • 3. 总结

1. 算法介绍

小内存分配算法常用于内存大小在 2M 字节以下的内存单元分配管理,小内存分配算法是一种动态内存管理算法,且在内存块释放时支持合并处理以减少内存碎片,是一种高效的内存分配算法,常用于嵌入式MCU中的内存管理。

此内存分配算法源码参考自:rt-thread mem.c

2. 算法图解

2.1 约定

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

  • 内存单元:内存分配算法所管理的整个内存区域

  • 内存块:每次malloc申请时所从内存单元上分割下来的一块内存区域(包含内存块数据管理部分字节)

2.2 数据结构介绍

每一个分配的内存块均由一个数据结构管理,其位于申请的每一块内存块的头部,其数据结构如下:

struct heap_mem
{
    uint16_t magic;
    uint16_t used;
    int next;
    int prev;
}

对应成员含义如下:

  • magic: 代表一个内存段的头部,固定填充为一个固定字段,如 0x1ea0

  • used: 指示当前内存段是否使用

  • next / prev: 双向链表,通过此两个指针将每个内存段链接到链表进行管理

如下图所示:
在这里插入图片描述

2.3 初始化

将一块内存单元分配给小内存分配算法进行管理,其首先第一步便是对此内存单元进行初始化。

小内存分配算法其管理数据结构、信息将保存在此内存单元中,因此首先需要做的是:

  • 以默认值填充内存单元(可选)

  • 在对应内存地址上构造对应的数据结构,存储内存管理结构信息(重点)

  • 对传入的内存单元进行字节对齐处理,内存管理单元实际使用的起始地址将是传入地址进行字节对齐后的地址。这通常是为了提高cpu读写速率,内存对齐有利于提升 cpu 访问速度。

小内存管理算法在初始化的时候会在内存单元的头部和尾部各创建两个内存块,用来标记头和尾,此两个内存块内无有效内存,仅包含管理数据头,如下图所示:
在这里插入图片描述
同时会创建以下三个关键指针:

rt_uint8_t *heap_ptr;
struct heap_mem *lfree;
struct heap_mem *heap_end;

其各自的含义分别是:

  • heap_ptr: 指向内存单元的有效起始地址,这个地址不一定时内存单元的地址,其是内存单元进行字节对齐之后的地址
  • lfree: 此指针随着内存单元的不断申请和释放会不停的移动,其始终指向起始地址最小的那一块空闲内存块,注意是起始地址最小,而不是大小最小!
  • heap_end: 始终指向内存单元的最后一块内存,代表此内存单元的尾部

为了方便大家理解,从更全局的视角体会内存分配过程,后续图解中不再对每块内存头部进行展开;使用蓝色矩形代表 used = 0 的空闲块的管理头;使用粉红色矩形代表 used = 1 的已使用块的管理头。

初始化之后的内存单元如下图所示:
在这里插入图片描述

2.4 第一次 malloc 40字节

在这里插入图片描述
lfree 所在的节点开始,遍历整个链表,找到具备申请字节大小(40Byte)+ 内存块管理头大小的空间,之后进行分配,此时会将一个大的内存块进行拆分,拆分成两个,一个用于此次的malloc申请,剩余的空闲块保留再链表上。

分配的时候会再创建一个新的内存块头部,记录被剩余的那个空闲块,并将其链接到链表里。

注意 malloc 返回的地址实际是内存管理头后的一个字节地址!

此外记得移动 lfree 指针指向新的地址最小的内存块~

2.5 第二次 malloc 18 字节

在这里插入图片描述
和第一次一样,继续从 lfree 开始找能满足的空闲内存块:

  • 如果大小刚好满足申请内存块 + 管理头,则直接修改内存块管理头 used 字段为 1
  • 如果大小小于申请内存块 + 管理头,则继续往链表后面查找下一个空闲块
  • 如果大小大于申请内存块+ 管理头,则对此大内存块进行拆分,一部分用于用户使用,剩余的新建一个空闲块管理头将其链接到链表里面便于后续使用及管理。
  • 之后修改 lfree 节点指向新的地址最小的内存块

发现没有每次,都是从 lfree 这个节点下手从链表内寻找符合要求的空闲块,由于 lfree 用于指向地址最小的空闲内存块,因此寻找的时候可以每次单方向寻找即可,这也是为什么每次把内存分配完之后都需要调整 lfree 指向的根本原因了!

2.6 第三次 malloc 20字节

在这里插入图片描述
此次 malloc 和之前的 malloc 有一个差异点,从图中我们可以看到新申请的内存和前面的内存没有连续,之间存在部分空闲字节未使用,这是由于字节对齐所导致的细小碎片,比如我们内存单元是按照4字节对齐,那个此碎片大小可能为 1Byte、2Byte、3Byte,同样这是为了提升cpu访问速率而支持的内存对齐的,后面也讲到如何处理这些碎片,所以不用担心

2.7 第四次 malloc 40字节

在这里插入图片描述

2.8 第一次 free

好了,接下来要进行 free 操作了,传入 malloc 的时候返回的地址,在 malloc 的时候返回给用户的是此块内存块的内存管理头后的一个字节的地址,因此通过此地址往前移内存管理头大小的字节便可以找到对应的内存块管理头了!

同样通过 magic 字段验证此块管理头是正常的头,否则应该报错进入异常处理!

找到内存头之后将此块内存头的 used 字段修改为0,即可完成释放了,后面malloc的时候便可使用此块内存,如此简单!对了,free的时候也需要记得判断是否需要移动 lfree 指针~
在这里插入图片描述

2.9 第二次 free 内存合并处理碎片

紧接着,我们进行第二次 free 操作,如下图,操作依旧如第一次操作。
在这里插入图片描述
进行第二次 free 之后通过链表进行检查,发现 next 指向的下一个内存管理头,其 used 成员也是0,因此判断到此时可以进行内存块合并了!那合并又是如何实现的呢?其实这也非常的简单!

不就是将此次释放的内存块的 next 的内容修改为 next -> next 就好了嘛!!!也就是 next 指向下一块内存管理头内记录的它的下一块内存,这样把后面这块空闲内存从链表里面移除掉了,后续malloc分配的时候,后面的空间就都是我的了!

ps: 当然记得把后面的后面那块的 prev 也修改为 prev->prev
在这里插入图片描述

此外,经过上面的这一手骚操作,之前残留的几个字节为了字节对齐而造成的碎片是不是也合并进去了,碎片也就处理完了!

到此为止,大家有没有想过,这样子的话,搞个单向链表不就好了吗,干嘛大费周章搞个双向链表,是不是有点浪费?

其实并没有,上面我们展示的是第二次释放的时候,释放的内存后面有一个空闲内存,如果其前面也有一个空闲内存,那么如何快速按照上述操作进行内存合并呢?这不就要使用到 prev 指针了,这也就是为什么需要使用双向链表的原因了!

3. 总结

以上便是对于小内存分配算法的完整图解,思路还是很清晰的,理解清楚了之后不妨思考一下此算法的优缺点是什么,欢迎大家将各自的思考在评论区进行交流讨论!也建议大家对其源码进行阅读,有了这份指南再去阅读源码,相信会吃的更加透彻!


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

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


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


相关推荐:

  • 专栏:文件系统专栏(点击跳转)

  • 专栏:RT-Thread内核(点击跳转)

  • 专栏:物联网ESP32(点击跳转)

  • 专栏:电机控制专栏(点击跳转)

  • 其他专栏,去主页看看吧~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2048475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LINUX服务器部署准备

文章目录 配置环境变量NODE下载解压安装 NGINX下载NGINX下载GCC并安装解压安装启动NGINX MAVEN下载解压安装配置环境 TOMCAT下载兼容版本解压安装开启远程访问 REDIS下载解压安装配置远程使用关闭保护模式 配置环境变量 vi /etc/profile source /etc/profile解压成功之后、运行…

安装IDEA2021.2.1(含安装包)及其扩展设置

一、下载 通过百度网盘分享的文件:ideaIU-2021.2.1.exe 链接:https://pan.baidu.com/s/1cCUHNm0dpWlfkxf5RCEgfw 提取码:v62e 二、安装 安装视频网址:Java基础概念-12-idea的概述和下载安装_哔哩哔哩_bilibili 三、idea中的第一…

Postman内置动态参数和自定义动态参数

业务场景 现在有两个接口,接口1:获取接口统一鉴权码token接口,接口2:创建标签接口,标签接口的创建依赖接口1返回的鉴权码,即需要获取access_token的值,替换ACCESS_TOKEN。且接口2中标签名不能和…

【计算机硬件内存】

内存插槽中间通常有个突起物将整个插槽稍微切分成为两个不等长的距离, 这样的设计可以让使用 者在安装内存时,不至于前后脚位安插错误,是一种防呆的设计喔。 前面提到CPU所使用的数据都是来自于内存(main memory)&…

Java流程控制04:while循环结构

教学视频链接:https://www.bilibili.com/video/BV12J41137hu?p38&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5https://www.bilibili.com/video/BV12J41137hu?p38&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 在Java中,while 结构是一个…

【C语言】深入讲解指针(中)

文章目录 前言函数指针函数指针变量的创建函数指针变量的使用两段有趣的代码typedef 关键字 函数指针数组函数指针的使用最后 前言 上一章深入讲解指针(上)我们对字符指针、数组指针、指针和数组传参进行了讲解,本章将对函数指针进行讲解&am…

Java、python、php版的大学生家教预约服务系统的设计与实现(源码、调试、LW、开题、PPT)

💕💕作者:计算机源码社 💕💕个人简介:本人 八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流&…

滚珠丝杆磨损评估:何时需进行研磨修复的关键指标?

滚珠丝杆是一种常见的机械传动元件,是将回转运动转化为直线运动,或将直线运动转化为回转运动的理想产品,在工具机械和精密机械上最常使用的传动元件。由于长时间使用或使用方法不当,滚珠丝杆可能会出现磨损、折裂、腐蚀等问题。影…

开机启动项检查

目录 介绍步骤总结 介绍 Windows在启动的时候,会自动加载很多程序。这些程序的自启动,带来了便利,但如果是恶意的自启动程序,我们就要关闭掉。 步骤 1、在开机后,打开了一个flag文件,里面填写了一个flag…

【解析几何笔记】4.向量分解定理的应用

4.向量分解定理的应用 4.1 简单比(定比) 【例1.3】(由 ( A , B , D ) , ( C , A , F ) (A,B,D),(C,A,F) (A,B,D),(C,A,F)可以看出用 A C ⃗ , A B ⃗ \vec{AC},\vec{AB} AC ,AB 和从A点做起点的向量方便解题,再看题目所求的简单比…

Spring 事务配置类,完成数据库的转账

1、完成基本的三层架构 1.1创建Account表 创建实体类 Account 1.2 Service层写入 AccountService 接口 Service层 下写 impl 包定义 AccountServiceImpl 类 实现接口 AccountService Service Transactional RequiredArgsConstructor public class AccountServiceImpl impleme…

【网络】高并发场景处理:线程池和IO多路复用

文章目录 短时间内有大量的客户端的解决方案线程池IO 多路复用 短时间内有大量的客户端的解决方案 创建线程是比较经典的一种服务器开发模型,给每个客户端分配一个线程来提供服务 但一旦短时间内有大量的客户端,并且每个客户端请求都是很快的&#xff…

电路笔记(PCB):串扰的原理与减少串扰的几种方法

串扰 串扰(Crosstalk)是指在电路中,一条信号线上的电磁干扰不经意间耦合到另一条相邻的信号线上,从而影响其正常信号传输的现象。串扰会导致相邻信号线上的信号出现畸变或噪声,从而影响信号的完整性和电路的正常工作。…

【ARM+Codesys 客户案例 】 基于RK3568/A40i/STM32+CODESYS在智能制造中的应用案例:液压动力装置

Poppe Potthoff是一家专门从事高压领域技术研发和产品制造的集团公司,该公司为汽车行业、特种车辆行业、船舶行业等开发制造先进的技术产品。 信迈提供ARMCodesys国产化定制。 Poppe Potthoff在其诺德豪森工厂研发用于爆破测试,自应力加工、脉冲测试和…

深度学习-------------------使用块的网络VGG

目录 VGGVGG块VGG架构进度总结 使用块的网络(VGG)VGG块VGG网络观察每层输出的形状该部分总代码 训练模型 VGG AlexNet比LeNet更深更大,以得到更好的精度 能不能更深和更大?该如何更深更大? 选项: 更多的…

阿里Qwen2开源大模型本地部署及调试全攻略

阿里Qwen2开源大模型本地部署及调试全攻略 #Qwen2系列大模型性能卓越,超越业界知名模型。开源后受到AI开发者关注,支持多种语言,提升多语言理解。在预训练和微调上优化,实现智能水平提升。Qwen2系列模型在各项能力上均领先&#…

基于NXP i.MX8M Mini+FPGA医疗超声诊断设备

医疗超声诊断设备 超声诊断仪,又称超声医疗影像设备,是利用超声波的反射、折射和衍射,对人体内部结构进行探查的仪器。由于超声诊断的无损伤、非介入、经济实用、应用范围广等特点,超声诊断仪也成为目前医疗领域普遍使用的医疗器…

C++_进阶:二叉搜索树

文章目录 1. 二叉搜索树是什么2. 二叉搜索树的基本操作3. 二叉搜索树的实现4 二叉搜索树的性能分析 1. 二叉搜索树是什么 二叉搜索树(BST,Binary Search Tree)又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树: 若它的左子树不…

汉诺塔问题详解及扩展(c++)

汉诺塔(Hanoi Tower)问题是一个著名的数学问题,它涉及到递归算法。问题的背景来源于一个传说:在印度的一个寺庙里,有三根金刚石柱和64个直径大小不一的金盘。僧侣们被命令将这些金盘从一根柱子按照从小到大的顺序移动到…

北京移民服务机构亨瑞移民:汇集全球专业顾问 30年致力全球生活方式

01      北京移民服务机构亨瑞集团成立于1992年,作为一站式海外综合服务专业平台,30年来致力于为有意赴海外求学、拓展事业、居住、生活、工作的各行业人士提供全球教育规划、身份规划及资产全球配置解决方案。    北京移民服务机构亨瑞集团公司…