Skip to content

RT-Thread内存管理

RT-Thread使用两种方法进行内存管理, 动态内存堆管理以及静态内存池管理

特点

RTOS对于时间的要求非常高

  1. 分配内存的时间必须是确定的。实时系统必须要保证内存块的分配过程在可预测的确定时间内完成,否则实时任务对外部事件的响应也将变得不可确定。
  2. 对于需要长时间使用不能重启的嵌入式系统来说不能出现内存的碎片化
  3. 使用的时候需要高效, 因为嵌入式的内存一般都不大

RT-Thread内存堆管理又根据具体内存设备提供了不同的内存分配管理算法

  • 小内存块的分配管理(小内存管理算法)
  • 大内存块的分配管理(slab管理算法)
  • 多内存堆的分配情况(memheap管理算法)

内存堆管理

用于管理一段连续的内存空间

RT-Thread将“ZI段(未初始化的全局变量)结尾处”到内存尾部的空间用作内存堆

image-20240207204055281

内存堆可以在当前资源满足的情况下,根据用户的需求分配任意大小的内存块。而当用户不需要再使用这些内存块时,又可以释放回堆中供其他应用分配使用

小内存管理算法

是一个简单的内存分配算法。初始时,它是一块大的内存。当需要分配内存块时,将从这个大的内存块上分割出相匹配的内存块,然后把分割出来的空闲内存块还回给堆管理系统中。每个内存块都包含一个管理用的数据头,通过这个头把使用块与空闲块用双向链表的方式链接起来

image-20240207204439515

magic:变数(或称为幻数),它会被初始化成0x1ea0(即英文单词heap),用于标记这个内存块是一个内存管理用的内存数据块;变数不仅仅用于标识这个数据块是一个内存管理用的内存数据块,实质也是一个内存保护字:如果这个区域被改写,那么也就意味着这块内存块被非法改写

used:指示出当前内存块是否已经分配。

在使用的时候会遍历这一个链表, 直到找到第一个必须要的内存大的块, 然后进行分割

在每一次分割的时候都会使用12字节作为信息记录的节点, 释放的时候看一看前后是不是可以相连, 是的话进行连接

slab管理算法

slab分配器会根据对象的大小分成多个区(zone),也可以看成每类对象有一个内存池

image-20240207205000301

一个zone的大小在32K到128K字节之间,分配器会在堆初始化时根据堆的大小自动调整。系统中的zone最多包括72种对象,一次最大能够分配16K的内存空间,如果超出了16K那么直接从页分配器中分配。

每个zone上分配的内存块大小是固定的,能够分配相同大小内存块的zone会链接在一个链表中,而72种对象的zone链表则放在一个数组(zone_array[])中统一管理

主要的操作:

  1. 内存分配

在分配的时候首先会从链表里面找, 没有找到的话则向页分配器分配一个新的zone,然后从zone中返回第一个空闲内存块。

如果链表非空,则这个zone链表中的第一个zone节点必然有空闲块存在

如果分配完成后,zone中所有空闲内存块都使用完毕,那么分配器需要把这个zone节点从链表中删除

  1. 内存释放

分配器需要找到内存块所在的zone节点,然后把内存块链接到zone的空闲内存块链表中

如果此时zone的空闲链表指示出zone的所有内存块都已经释放,即zone是完全空闲的,那么当zone链表中全空闲zone达到一定数目后,系统就会把这个全空闲的zone释放到页面分配器中去

memheap管理算法

适用于系统含有多个地址可不连续的内存堆

用户只需要在系统初始化时将多个所需的memheap初始化,并开启memheap功能就可以很方便地把多个memheap(地址可不连续)粘合起来用于系统的heap分配。

开启memheap之后原来的heap功能将被关闭,两者只可以通过打开或关闭RT_USING_MEMHEAP_AS_HEAP来选择其一

image-20240207205604871

实际使用

初始化

c