FreeRTOS内存管理
Posted xw-kaka
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FreeRTOS内存管理相关的知识,希望对你有一定的参考价值。
简介
Freertos的内存管理分别在heap_1.c,heap_2.c,heap_3.c,heap_4.c,heap_5.c个文件中,选择合适的一种应用于嵌入式项目中即可。
本文的图片中
红色部分Block代表:在内存对齐过程中舍弃掉的部分字节。
蓝色部分Block代表:链表结构体头,包含可以分配的内存大小和Next指针。
绿色部分Block代表:实际可分配给用户的内存。
黄色部分Block代表:已经分配给用户的内存。
heap_1.c
特点:
- 最简单的内存分配算法。
- 分配后无法释放内存。
- 支持1/2/4/8/16/32多种内存对齐方式。
- 线程安全。
初始化
- ucHeadp数组代表整个堆内存空间。
- xNextFreeByte = 0。
- 初始化以后pucAlignedHeap指针会指向内存对齐后的第一个位置。
?
*pvPortMalloc():
- 依次返回pvReturn(pucAlignedHeap+xNextFreeByte)所指向的地址,并更新xNextFreeByte大小。
?### vPortFree():
- 无法使用,传入的指针非空会进入断言。
heap_2.c
特点:
- 采用链表结构管理,按内存块大小排序。
- 分配后可以释放内存,但是会产生内存碎片。
- 支持1/2/4/8/16/32多种内存对齐方式。
- 线程安全。
初始化
- ucHeap数组代表整个堆内存空间。
- 初始化以后pucAlignedHeap指针会指向内存对齐后的第一个位置。
- xStart表示链表头,pxFirstFreeBlock代表第一块可分配空间,xEnd代表链表尾。
?
*pvPortMalloc():
- 按内存字节对齐方式调整实际分配大小。(实际大小=内存对齐+链表结点结构体大小)
- 遍历整个内存链表,如果找到足够分配的内存Block头,则加上结构体头偏移量,将pvReturn位置记录待返回给用户,并将该结点从链表中移除。
- 分配完成后,如果剩余的内存大小仍然大于最小的BlockSize(包含链表结构体),就将该Block切割,并按照BlockSize从小到大的方式插入空闲内存链表。
?###vPortFree():
- Free的过程非常简单,只是根据传入的指针参数,反向找到结构体头,然后根据该节点BlockSize从小到大重新插入空闲内存链表中即可。
总结:
- 内存的分配和释放过程是线程安全的。
- 在内存分配和释放过程会产生内存碎片,所以heap_2.c不适用于频繁地内存分配的场合。试想这样一种情况:不停地进行小片内存分配(比如:8个字节)直到内存用完,分配完成后全部重新Free,由于结点信息仍然存在,将导致以后都无法分配超过8个字节的内存。
heap_3.c
特点:
- 使用标准库中的malloc和free方法。
- 无法在中断中分配和释放内存。
- 线程安全。
在标准库的基础上,简单地加上线程安全的处理,保证malloc不会被线程切换打断。
heap_4.c
特点:
- 采用链表结构管理,按地址大小排序。
- 分配后可以释放内存,不会产生内存碎片。
- 支持1/2/4/8/16/32多种内存对齐方式。
- 线程安全。
初始化
- ucHeadp数组代表整个堆内存空间。
- 初始化以后pucAlignedHeap指针会指向内存对齐后的第一个位置。
- xStart表示链表头,pxFirstFreeBlock代表第一块可分配空间,xEnd代表链表尾。和heap_2.c不一致的是这里的链尾结构体也分配在ucHeap内存中。
?
*pvPortMalloc():
- 按内存字节对齐方式调整实际分配大小。(实际大小=内存对齐+链表结点结构体大小)
- 遍历整个内存链表,如果找到足够分配的内存Block头,则加上结构体头偏移量,将pvReturn位置记录待返回给用户,并将该结点从链表中移除。
- 如果剩余的内存大小仍然大于最小的BlockSize(包含链表结构体),就将Block切割,并按照地址从小到大的方式插入内存链表,并更新xFreeBytesRemaining。
?###vPortFree():
- 根据传入的指针参数,反向找到结构体头,然后迭代空闲链表,根据该节点的地址从低到高,找到相应的插入位置。
- 当Free的时候,有两种情况,一种是连续(如图中黄色块3),一种是不连续(如图中黄色块1,2)。
- 插入空闲内存链表后,如果该节点与后面的节点是连续的,则将这两个节点整合成一个大的节点。
总结:
- 内存的分配和释放过程是线程安全的。
- 和heap_2.c非常相似,最大不同点在于释放内存的时候不会产生碎片,具体做法是在插入空闲内存链表的时候多了一步操作:如果两个空闲节点在内存上是连续的,则将这两个节点重新整合成一个。
- ?另外一点和heap_2.c不同的地方在于,空闲内存链表排序方式不一样,heap_2.c是按照blockSize排序,而heap_4.c是按照内存地址排序,所以heap_4.c的空闲链表在内存上是很容易整合的,而heap_2.c由于没有按内存地址排序,所以整合比较麻烦。
heap_5.c
特点:
- 采用链表结构管理,按地址大小排序。
- 分配后可以释放内存,不会产生内存碎片。
- 支持1/2/4/8/16/32多种内存对齐方式。
- 线程安全。
- 可以自定义内存区。
Malloc和Free方法和heap_4.c一模一样。
区别在与heap_4.c使用prvHeapInit()函数将ucHeap这个全局变量作为内存区,而heap_5.c没有这个prvHeapInit()函数,而是提供了另一个函数vPortDefineHeapRegions(),自己定义内存区。
以上是关于FreeRTOS内存管理的主要内容,如果未能解决你的问题,请参考以下文章