FreeRTOS提供了五种内存管理的方式,下文将对以下五种内存分配进行说明:
1.Heap_1
Heap_1 堆大小通过FreeRTOSConfig.h中的configTOTAL_HEAP_SIZE定义设置,在源码通过数组的总大小configTOTAL_HEAP_SIZE(bytes)定义设置,允许使用pvPortMalloc(),但没有实现vPortFree()。
当调用pvPortMalloc()时,heap_1分配方案将一个简单数组细分为更小的块。这个数组被称为FreeRTOS堆。
每个创建的任务都需要从堆中分配一个任务控制块(TCB)和一个堆栈。下图演示了heap_1如何将简单数组细分为创建任务。
![](https://img-blog.csdnimg.cn/450408a0fbf44d1cbf15f40be26a242b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6YCD6LeRZGXmnKjlgbY=,size_20,color_FFFFFF,t_70,g_se,x_16)
如图可见,Heap_1不能删除栈区,随着不断申请内存,有栈溢出风险,在通常应用中不建议使用此种内存分配方法。
2.Heap_2
Heap_2 堆大小通过FreeRTOSConfig.h中的configTOTAL_HEAP_SIZE定义设置,在源码通过数组的总大小configTOTAL_HEAP_SIZE(bytes)定义设置,允许使用pvPortMalloc()和vPortFree(),但是Heap_2不会将相邻的块合并成一块,因此更容易碎片化。
每个创建的任务都需要从堆中分配一个任务控制块(TCB)和一个堆栈。下图演示了heap_2如何将简单数组细分为创建任务。如1中创建了三个Task;2中删除中间Task;2->3创建一个和删除task大小一样的task;2->4创建了一个比之前删除的task堆更大的task。
![](https://img-blog.csdnimg.cn/56b610fdd8374cc5a546293f0ecf810c.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6YCD6LeRZGXmnKjlgbY=,size_19,color_FFFFFF,t_70,g_se,x_16)
如果删除创建相同大小的,不存在内存碎片化风险,如果控制不了,则会产生较多的堆栈碎片
Heap_2比malloc()和free()的大多数标准库实现要快。
3.Heap_3
Heap_3.c使用标准库malloc()和free()函数,因此堆的大小是由连接器配置定义的,configTOTAL_HEAP_SIZE设置没有影响。
Heap_3通过临时挂起FreeRTOS调度器使malloc()和free()线程安全。
4.Heap_4
与heap_1和heap_2一样,heap_4的工作原理是将数组细分为更小的块。与前面一样,堆大小通过FreeRTOSConfig.h中的configTOTAL_HEAP_SIZE定义设置,在源码通过数组的总大小configTOTAL_HEAP_SIZE(bytes)定义设置,允许使用pvPortMalloc()和vPortFree(),
Heap_4使用第一适合算法来分配内存。与heap_2不同,heap_4将相邻的空闲内存块合并成一个更大的块,这将内存碎片的风险降到最低。
first fit算法确保pvPortMalloc()使用第一个足够容纳请求字节数的空闲内存块。
每个创建的任务都需要从堆中分配一个任务控制块(TCB)和一个堆栈。下图演示了heap_4如何将优化堆栈碎片。
![](https://img-blog.csdnimg.cn/f8deeacee7e74762864f300886d010b1.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6YCD6LeRZGXmnKjlgbY=,size_20,color_FFFFFF,t_70,g_se,x_16)
通常建议使用heap_4作为内存管理方案。通常heap_4通常使用内部快速内存,而不是缓慢的外部内存。
默认情况,该堆的起始地址由自动连接,但是,如果configAPPLICATION_ALLOCATED_HEAP = 1,堆数组的起始地址可以由应用程序设置起始地址,且定义 uint8_t ucHeap[configTOTAL_HEAP_SIZE ]数组,数组的地址根据不同的编译器来决定写法。IAR编译器声明数组并将数组放置在绝对内存地址0x20000000所需的语法:
uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] @ 0x20000000;
5.Heap_5
Heap_5与Heap_4分配和释放内存方法一样,与Heap_4不同的是heap_5并不局限于从一个静态声明的数组中分配内存;Heap_5可以从多个和分离的内存空间分配内存。heap_5对于FreeRTOS运行的系统提供的RAM在系统内存映射中不是一个连续的(没有空间)块时非常有用。
在编写时,heap_5是唯一提供的在调用pvPortMalloc()之前必须显式初始化的内存分配方案。使用vPortDefineHeapRegions() API函数初始化Heap_5。当使用heap_5时,必须在创建任何内核对象(任务、队列、信号量等)之前调用vPortDefineHeapRegions()。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)