深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解

5  Freertos 内存管理

芯片中最为稀缺珍贵的往往是存储资源,为了更好的利用它们,开发者不得不变得吝啬分配、斤斤计较到每一个字节。

FreeRtos V8.0.1针对动态内存分配提供了四种方案,分别放在heap1、heap2、heap3、heap4文件中。

5.1 分配方式  heap1

heap1分配方法最为简单,代码量也相对较小,heap1只能申请不能回收,适合任务、队列等不需要执行删除操作的工程。

ucHeap占据的整块内存既为可申请的堆空间,空间大小由configTOTAL_HEAP_SIZE定义。

分配之前首先对堆的起始地址做偶对齐,这有可能会使一些起始的字节作为“占位”而丢弃掉,最终得到堆有效空间使用configADJUSTED_HEAP_SIZE代替。

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第1张图片

(堆初始化)

Heap1分配时使用xNextFreeByte始终记录堆中可分配的首地址,起始值为0。

若初始化后需要申请20字节:

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第2张图片

(申请20字节)

第二次申请30字节:

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第3张图片

(申请30字节)

5.2 分配方式 heap2

Heap2中每个内存块都有对应结构体的记录链表和块大小,链表将空闲块按照块大小升序相连。Start和end结构体作为索引独立于堆区,end作为结束标识xBlockSize总是等于堆区总大小。

Heap2初始化堆区后图:

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第4张图片

(heap2初始化后)

5.2.1 heap2申请内存

如果程序需要申请A、B、C三块内存,需要的空间大小为B>A>C,使用heap2的申请分配图如下:

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第5张图片

(申请A空间)

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第6张图片

(申请B、C空间)

5.2.2 heap2回收内存

Heap2回收时将内存块按照升序方式插入链表。假设剩余的D空间大小等于A,程序分别释放B、A、C内存,释放后堆区如下:

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第7张图片

(释放B内存后

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第8张图片

(释放A内存后

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第9张图片

(释放C内存后

内存链上的内存按照块大小递增,记录块信息的结构体随着分配逐渐增加,永远得不到释放。一旦程序频繁申请小块内存,即使释放后也无法申请大内存块。

5.3 分配方式 heap3

Heap3使用了库中的malloc和free,此时堆区已经脱离freertos控制,configTOTAL_HEAP_SIZE成为无效参数。没有源码,,,,先不做分析~

5.4 分配方式 heap4

Heap4中每个内存块都有对应结构体的记录链表和块大小,链表将空闲块按照地址升序相连。Start结构体作为索引独立于堆区,end属于堆区一部分,所以去除一个结构体的size才是堆实际分配范围。

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第10张图片

(heap4初始化后的堆区)

5.4.1 heap4申请内存

每当申请出空闲块后都会对应产生一个新的结构体,这些结构体会占据一部分堆空间。申请内存块A后堆区图:

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第11张图片

(申请A内存后)

再次申请B、C内存块:

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第12张图片

(申请B内存后)

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第13张图片

(申请C内存后)

5.4.2 heap4 回收内存

heap4在回收内存时会尝试将零散的内存块进行合并,减少碎片。

假设在申请A、B、C之后,B内存使用完毕需要释放掉,B块的上下都没有相邻的空闲内存,所以只插入空闲链表就可以完成释放。如图:

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第14张图片

(释放B后)

释放A时,存在相邻的B区,两块内存会进行拼接,B块的结构体也被合并,如图:绿色区是被回收的内存

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第15张图片

(释放A后)

回收C块时,上下都存在空闲区,回收工作分为两个步骤进行:

深度解剖~ FreeRtos阅读笔记5 FreeRtos内存管理详解_第16张图片

(释放C

5.5 阅读小结

相同点

除heap3外,都使用大数组作为堆区进行分配,这看起来比较浪费,即使程序没有申请任何空间,堆区占据的内存在程序编译前就已经确定。

Heap2与heap4都需要为记录内存块信息而消耗一定堆空间。

调用相同,统一使用pvPortMalloc和vPortFree,方便heap文件更换。

进行堆操作时都没有屏蔽中断,只是将调度器挂起。所以FreeRtos堆操作不能在中断里使用,如果一定要实现的话,线程中每一个堆操作的地方如创建任务、信号量、队列等~都要先屏蔽中断,这会使FreeRtos调度器实时性下降。

区别

四种方式主要在分配方法上存在差异:

Heap1分配最为简单迅速,它适合只申请不释放的工程。

Heap2进行频繁申请释放后会造成较多的碎片,适合只申请固定大小内存的工程。

Heap4像是Heap2的升级版,分配方式几乎相同,在回收时添加了内存块拼接以尝试消除碎片。

你可能感兴趣的:(嵌入式,freertos,stm32,arm,程序人生)