FREERTOS学习笔记十-内存管理
1.FreeRTOS内存管理方式
1.1 heap_1.c中的内存分配
? 动态内存分配需要一个内存堆,FreeRTOS中的内存堆为ucHeap[],大小为configTOTAL_HEAP_SIZE。不管是哪种内存分配方法,它们的内存堆都为ucHeap[],而且大小都是configTOTAL_HEAP_SIZE。
特点: ①适用于那些一旦创建好任务、信号量和队列就再也不会删除的应用,实际上大多数的FreeRTOS应用都是这样的。 ②具有可确定性(执行所花费的时间大多数都是一样的),而且不会导致内存碎片。 ③代码实现和内存分配过程都非常简单,内存是从一个静态数组中分配到的,也就是适合于那些不需要动态内存分配的应用。
1.2 heap_2.c中的内存分配
? heap_2.c提供了一个更好的配算法,不像heap_1.c那样,heap_2.c提供了内存释放函数**。**heap_2.c不会把释放调的内存块合并成一个大块,这样有一个缺点,随着你不断的申请内存,内存堆就会被分为很多个大小不一的内存(块),也就是会导致内存碎片!
特点: ①可以使用在那些可能会重复的删除任务、队列、信号量等的应用中,要注意有内存碎片产生! ②如果分配和释放的内存大小是随机的,那么就要慎重使用了。 ③如果应用中的任务、队列、信号量和互斥信号量具有不可预料性(如所需的内存大小不能确定,每次所需的内存都不相同,或者说大多数情况下所需的内存都是不同的)的话可能会导致内存碎片。 ④具有不可确定性,但是也远比标准C中的mallo()和free()效率高!
1.3 heap_3.c中的内存分配
? 这个分配方法是对标准C中的函数malloc()和free()的简单封装,FreeRTOS对这两个函数做了线程保护。
特点:
①需要编译器提供一个内存堆,编译器库要提供malloc()和free()函数。比如STM32的话可以通过修改启动文件中的Heap_Size来修改内存堆的大小。 ②具有不确定性。 ③可能会增加代码量。 注意:在heap_3.c中configTOTAL_HEAP_SIZE是没用的!
1.4 heap_4.c中的内存分配
? heap_4.c提供了一个最优的匹配算法,不像heap_2.c,heap_4.c会将内存碎片合并成一个大的可用内存块,它提供了合并算法。内存堆为ucHeap[],大小为configTOTAL_HEAP_SIZE。可以通过函数xPortGetFreeHeapSize()来获取剩余的内存大小。
特点:
①可是用在那些需要重复创建和删除任务、队列、信号量和互斥信号量等的应用中。 ②不会像heap_2.c那样产生严重的内存碎片,即使分配的内存大小是随机的。 ③具有不确定性,但是远比C标准库中的malloc()和free()效率高。heap_4.c非常适合于那些需要直接调用函数pvPortMalloc()和vPortFree()来申请和释放内存的应用。
1.5 heap_5.c中的内存分配
? heap_5.c使用了和heap_4.c相同的合并算法,内存管理实现起来基本相同,但是heap_5.c允许内存堆跨越多个不连续的内存段。比如STM32的内部RAM可以作为内存堆,但是STM32内部RAM比较小,遇到那些需要大容量RAM的应用就不行了,如音视频处理。
1.6 总结
? FreeRTOS官方提供的5种内存分配方法已经介绍完,heap_1.c最简单,但是只能申请内存,不能释放。heap_2.c提供了内存释放函数,用户代码也可以直接调用函数pvPortMalloc()和vPortFree()来申请和释放内存,但是heap_2.c会导致内存碎片的产生!heap_3.c是对标准C库中的函数malloc()和free()的简单封装,并且提供了线程保护。heap_4.c相对与heap_2.c提供了内存合并功能,可以降低内存碎片的产生,我们移植FreeRTOS的时候就选择了heap_4.c。heap_5.c基本上和heap_4.c一样,只是heap_5.c支持内存堆使用不连续的内存块。 ————————————————
以上原文链接:https://blog.csdn.net/weixin_44502943/article/details/121017944
2.CubeMX查看内存管理方式
3.程序测试1——查看剩余内存
3.1程序代码
void StartKEY_Task(void const * argument)
{
uint16_t ProducerValue = 1;
for(;;)
{
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == 0)
{
osDelay(10);
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == 0)
{
osThreadSuspendAll();
printf("使用RAM:%d/100 \r\n",100 - xPortGetFreeHeapSize()*100/configTOTAL_HEAP_SIZE);
osThreadResumeAll();
}
}
while(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == 0)
{
osDelay(10);
}
osDelay(1);
}
}
3.2运行结果
4.程序测试2——申请与释放内存
4.1程序源码
void StartKEY_Task(void const * argument)
{
void *home;
for(;;)
{
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == 0)
{
osDelay(10);
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == 0)
{
osThreadSuspendAll();
printf("当前RAM:%d/100 \r\n",100 - xPortGetFreeHeapSize()*100/configTOTAL_HEAP_SIZE);
osThreadResumeAll();
home = pvPortMalloc(configTOTAL_HEAP_SIZE*4/100);
osThreadSuspendAll();
printf("申请之后RAM:%d/100 \r\n",100 - xPortGetFreeHeapSize()*100/configTOTAL_HEAP_SIZE);
osThreadResumeAll();
vPortFree(home);
osThreadSuspendAll();
printf("释放之后RAM:%d/100 \r\n",100 - xPortGetFreeHeapSize()*100/configTOTAL_HEAP_SIZE);
osThreadResumeAll();
}
}
while(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == 0)
{
osDelay(10);
}
osDelay(1);
}
}
4.2运行结果
|