嵌入式裸机内存动态管理的实现与讲解(一)

  • C 的标准库自带了mallocfree,为啥还要自己实现?标准库的函数占用空间较大,采用本文的实现可节约几KB的存储空间;
  • 为啥说裸机呢?因为带系统的软件系统一般都会带内存的动态管理函数供使用;
  • 内存碎片是什么? 首先明确一点,申请内存时会返回一个首地址,从首地址往后的 size 大小的空间都可用,这就说明 malloc必须返回一段连续的内存地址;有些内存动态管理算法是不支持碎片回收的,总是以新地址开始申请。
  • 已验证,标准 C 库的mallocfree的函数不支持内存碎片回收;测试方法:循环多次申请->释放较小的内存块,然后再申请大的内存块将失败。
  • 本文说明的算法是支持内存碎片化回收的,采用把相邻的空闲内存块进行合并的方法。

算法原理

数组我们比较熟悉,定义的数组必须实现固定大小,但实际编程中,有太多的情况我们事先无法预测这个数组该定义多大;没有内存动态管理的裸机系统的做法就是定义一个尽可能大的数组,浪费了RAM,也存在数组溢出的风险。

内存的动态管理:定义一个全局的静态大数组,先占个内存的坑,别让编译器给释放或优化掉了;这就是属于用户的内存池,进行自我的内存管理;

这个大的内存池怎么管理比较好呢?本文采用单向链表的形式进行管理,如下图;在这里插入图片描述
原理说明:

  • 你可能会说,每个内存块都要占用几个字节用来存储链表指针和内存块大小,不是浪费吗?有舍才能有得,得 > 舍就是值得;

  • 第一次申请内存之前,A_BlockB_Block是没有的,pxFirstFreeBlock内存块的可用大小为大的全局数组所剩空间,此时链表只有一个内存块,按申请的内存大小将pxFirstFreeBlock内存块分割成两个;

  • 后面每次申请内存时,会按照已有的内存块去遍历链表,满足大小能否满足,满足了,剩余部分是否够再分割成一个块的;

  • 你可以想象,这个数组变成了好多个内存块,2、4、12、23;

  • 如果算法按上述实现,将会产生内存碎片,申请新的内存比已经申请过的内存块大时,就必须开辟新空间,链表中的很多内存将被浪费;

  • 相邻地址的空闲内存块进行合并:每次释放内存块时,会将其重新放入空闲链表中,此时会判断前后的内存块和自己地址是否是相邻的,是就合并内存块,即内存碎片的回收

代码实现

敬请期待,最迟三天后更新~