二十一、FreeRTOS之FreeRTOS内存管理

news/2024/12/29 11:19:48/

本节需要掌握以下内容:

1FreeRTOS内存管理简介(了解)

2FreeRTOS内存管理算法(熟悉)

3FreeRTOS内存管理相关API函数介绍(熟悉)

4FreeRTOS内存管理实验(掌握)

5,课堂总结(掌握)

一、FreeRTOS内存管理管理(了解)

在使用FreeRTOS创建任务、队列、信号量等对象的时候,一般都提供了两种方法:

动态方法创建:自动的从FreeRTOS管理的内存堆中申请创建对象所需的内存,并在对象删除后,可将这块内存释放回FreeRTOS管理的内存堆

静态方法创建:需要用户提供各种内存空间,并且使用静态方式占用的内存一般固定下来了,即使任务、队列被删除后,这些被占用的内存空间一般没有其他途径。

总结:动态方式管理内存相比静态方式更加灵活。

除了FreeRTOS提供的动态内存管理方法,标准的C库也提供了malloc()函数和free()来实现动态的申请和释放内存。

疑问:为啥不用标志的C库自带的内存管理算法?

  • 因为标准的C库的动态内存管理方法有如下几个缺点:
  • 占用大量的代码空间,不适用在资源紧缺的嵌入式系统中
  • 没有线程安全的相关机制
  • 运行有不确定性,每次调用这些函数花费的事件可能都不相同
  • 内存碎片化

因此FreeRTOS提供了多种动态内存管理的算法,可针对不同的嵌入式系统!

二、FreeRTOS内存管理算法(熟悉)

FreeRTOS提供了5种动态内存管理算法,分别为: heap_1heap_2heap_3heap_4heap_5如下所示:

算法

优点

缺点

heap_1

分配简单,时间确定

只允许申请内存,不允许释放内存

heap_2

允许申请和释放内存

不能合并相邻的空闲内存块会产生碎片、时间不定

heap_3

直接调用C库函数malloc()free() ,简单

速度慢、时间不定

heap_4

相邻空闲内存可合并,减少内存碎片的产生

时间不定

heap_5

能够管理多个非连续内存区域的 heap_4

时间不定

本专栏中使用的均为heap_4内存管理算法。

2.1 heap_1内存管理算法

heap_1只实现了pvPortMalloc,没有实现vPortFree;也就是说,它只能申请内存,无法释放内存!

如果你的工程,创建好的任务、队列、信号量等都不需要被删除,那么可以使用heap_1内存管理算法

heap_1的实现最为简单,管理的内存堆是一个数组,在申请内存的时候, heap_1 内存管理算法只是简单地从数组中分出合适大小的内存,内存堆数组的定义如下所示 :

  /* 定义一个大数组作为 FreeRTOS 管理的内存堆 */
 
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];

 heap_1内存管理算法的分配过程如下图所示:

注意: heap_1内存管理算法,只能申请无法释放!

2.2 heap_2内存管理算法

相比于heap_1内存管理算法,heap_2内存管理算法使用最适应算法,并且支持释放内存;

heap_2内存管理算法并不能将相邻的空闲内存块合并成一个大的空闲内存块;因此 heap_2 内存管理算法不可避免地会产内存碎片;

最适应算法:

假设heap有三块空闲内存(按内存大小由小到大排序):5字节,25字节,50字节

现在新创建一个任务需要申请20字节的内存

第一步:找出最小大的,能满足pvPortMalloc的内存:25字节

第二步:把它划分为20字节、5字节;返回这20字节的地址,剩下的5字节仍然是空闲状态,留给后续的pvPortMalloc使用

内存碎片化是由于多次申请和释放内存,但是释放的内存无法于相邻的空闲内存合并而产生的

适用场景:频繁的创建和删除任务,且所创建的任务堆栈都相同,这类场景下Heap_2没有碎片化的问题。 

2.3 heap_4内存管理算法

heap内存管理算法使用了首次适应算法,也支持内存的申请于释放,并且能够将空闲且相邻的内存进行合并,从而减少内存碎片的现象。

首次适应算法:

  • 假设heap由3块空闲内存(按内存地址由低到高排序):5字节、50字节、25字节
  • 现在新创建一个任务需要申请20字节的内存
  • 第一步:找出一个能满足pvPortMalloc的内存:50字节
  • 第二步:把它划分成20字节、30字节;返回这20字节的地址,剩下的30字节依然是空闲状态,留给后续的pvPortMalloc使用

heap_4内存管理算法会把相邻的空闲内存合并成一个更大的空闲内存,这有助于内存的碎片问题。

适用于这种场景:频繁的分配、释放不同大小的内存。

2.4 heap_5内存管理算法

heap_5内存管理算法是在heap_4内存管理算法的基础上实现的,但是heap_5内存管理算法再heap_4内存管理算法的基础上实现了管理多个非连续内存区域的能力

heap_5内存管理算法默认并没有定义内存堆,需要用户手动指定内存区域的信息,对其进行初始化。

问题:怎么指定一块内存?

使用如下结构体:

typedef struct HeapRegion
{
                          
uint8_t *   pucStartAddress;         /* 内存区域的起始地址 */
                         
size_t   xSizeInBytes;                   /* 内存区域的大小,单位:字节 */
} HeapRegion_t;

怎么指定多块不连续的内存?

Const  HeapRegion_t  xHeapRegions[] =
{
                          { (
uint8_t *)0x80000000, 0x10000 },           /* 内存区域 1 */
                         
{ (uint8_t *)0x90000000, 0xA0000 },           /* 内存区域 2 */
                         
{ NULL, 0 }                                                   /* 数组终止标志 */
};
vPortDefineHeapRegions(xHeapRegions);

适用场景:在嵌入式系统中,那些内存的地址并不连续的场景。

三、FreeRTOS内存管理相关API函数介绍(熟悉)

函数

描述

void * pvPortMalloc( size_t  xWantedSize );

申请内存

void  vPortFree( void * pv );

释放内存

size_t  xPortGetFreeHeapSize( void );

获取当前空闲内存的大小

void * pvPortMalloc( size_t  xWantedSize );                申请内存

l xWantedSize :申请的内存大小,以字节为单位;
返回值:返回一个指针 ,指向已分配大小的内存。如果申请内存失败,则返回 NULL;
void  vPortFree( void * pv );                                           释放内存
* pv:指针指向一个要释放内存的内存块

size_t  xPortGetFreeHeapSize( void );                    获取当前空闲内存的大小

返回值:返回当前剩余的空闲内存大小

四、FreeRTOS内存管理实验(掌握)

4.1、实验目的:

学习 FreeRTOS 内存管理,并观察内存在申请和释放过程中内存大小的变化情况

4.2、实验设计:

将设计三个任务:start_task、task1

两个任务的功能如下:

  • start_task:用来创建task1任务
  • task:用来按键扫描,当KEY0按下则申请内存,当KEY1按下则释放内存,并打印剩余内存信息

4.3 实验代码

demo.c

/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );/* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );/******************************************************************************************************//*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{    xTaskCreate((TaskFunction_t         )   start_task,(char *                 )   "start_task",(configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   START_TASK_PRIO,(TaskHandle_t *         )   &start_task_handler );vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL();               /* 进入临界区 */xTaskCreate((TaskFunction_t         )   task1,(char *                 )   "task1",(configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK1_PRIO,(TaskHandle_t *         )   &task1_handler );vTaskDelete(NULL);taskEXIT_CRITICAL();                /* 退出临界区 */
}/* 任务一,申请内存以及释放内存,并显示空闲内存大小 */
void task1( void * pvParameters )
{uint8_t key = 0, t = 0;uint8_t * buf = NULL;while(1) {key = key_scan(0);if(key == KEY0_PRES){buf = pvPortMalloc(30);                 /* 申请内存 */if(buf != NULL){printf("申请内存成功!\r\n");}else printf("申请内存失败\r\n");}else if(key == KEY1_PRES){if(buf != NULL){vPortFree(buf);                     /* 释放内存 */printf("释放内存!!\r\n");}                }if(t++ > 50){t = 0;printf("剩余的空闲内存大小为:%d\r\n",xPortGetFreeHeapSize());}vTaskDelay(10);}
}

初始化后的内存堆,如下:

插入新的空闲内存块,如下:

五、总结

 

 

FreeRTOS的知识点总结就暂时先告一段落了,后面将给大家带来几个相关的项目!

未完待预~

 


http://www.ppmy.cn/news/1266074.html

相关文章

【持更】python数据处理-学习笔记

1、读取excel /csv及指定sheet: pd.read_excel("路径",sheetname"xx") 修改列名df.rename 修改字符串类型到数字 pandas.to_numeric() 2、删除drop、去重drop_duplicates (1)空值所在行/列 行&am…

在做题中学习(31):电话号码的字母组合(全排列)

17. 电话号码的字母组合 - 力扣(LeetCode) 思路:既然要排列组合,就得先根据数字字符取出来 所以先定义一个string类的数组通过下标取到每个数字对应的映射。 string _numsTostr[10]{"","","abc"…

[Linux] nginx的location和rewrite

一、Nginx常用的正则表达式 符号作用^匹配输入字符串的起始位置$ 匹配输入字符串的结束位置*匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll” 匹配前面的字符一次或多次。如“ol”能匹配“ol”及“oll”、“olll”,但不能匹配“o”?匹配前面的字…

WhatsApp获客怎么做?记住这几个技巧!

一、背景介绍 随着全球数字化趋势的不断发展,越来越多的企业开始将目光转向数字化营销,WhatsApp作为一种国际通用的社交媒体平台,具有广泛的使用群体和强大的社交功能,成为了很多企业进行营销推广的重要渠道。 那么,…

Leetcode 2962. Count Subarrays Where Max Element Appears at Least K Times

Leetcode 2962. Count Subarrays Where Max Element Appears at Least K Times 1. 解题思路2. 代码实现 题目链接:2962. Count Subarrays Where Max Element Appears at Least K Times 1. 解题思路 这一题思路上同样很直接,就是找到最大的元素所在的全…

API接口使用方法(封装好的电商平台)

为了进行此平台API的调用,首先我们需要做下面几件事情。 1、 获取一个KEY。 点击获取 2、 参考API文档里的接入方式和示例。 3、查看测试工具是否有需要的接口,响应实例的返回字段是否符合参数要求。 4、利用平台的文档中心和API测试工具&#xff0c…

每日一题,头歌平台c语言题目

任务描述 题目描述:输入一个字符串,输出反序后的字符串。 相关知识(略) 编程要求 请仔细阅读右侧代码,结合相关知识,在Begin-End区域内进行代码补充。 输入 一行字符 输出 逆序后的字符串 测试说明 样例输入&…

【K8s】Kubernetes CRD 介绍(控制器)

文章目录 CRD 概述1. 操作CRD1.1 创建 CRD1.2 操作 CRD 2. 其他笔记2.1 Kubectl 发现机制2.2 校验 CR2.3 简称和属性 3. 架构设计3.1 控制器概览 参考 CRD 概述 CR(Custom Resource)其实就是在 Kubernetes 中定义一个自己的资源类型,是一个具…