四、内存管理

1、为什么需要自己实现内存管理

(1)RTOS涉及的内核对象:task、queue、semaphores和event group等。为了让FreeRTOS更容
易使用,这些内核对象一般都是动态分配:用到时分配,不使用时释放。使用内存的动态管理功能,简化了程序设计:不再需要小心翼翼地提前规划各类对象,简化API函数的涉及,甚至可以减少内存的使用。

(2)内存的动态管理是C程序的知识范畴,并不属于FreeRTOS的知识范畴,但是它跟FreeRTOS紧密相关。

(3)在C语言的库函数中,有mallc、free等函数管理内存,但是在FreeRTOS中,它们不适用。

  • 不适合用在资源紧缺的嵌入式系统中。
  • 这些函数的实现过于复杂、占据的代码空间太大。
  • 并非线程安全的(thread-safe)。
  • 运行有不确定性:每次调用这些函数时花费的时间可能都不相同。
  • 内存碎片化。
  • 使用不同的编译器时,需要进行复杂的配置。
  • 有时候难以调试。

2、堆栈

        我们经常"堆栈"混合着说,但堆和栈是不同的东西。

2.1、堆

(1)堆在计算机中有两种理解,这里介绍的是动态内存管理机制。

  • 堆是一种数据结构。
  • 堆是一种动态内存管理机制。

(2)堆是一种动态内存管理机制,它允许程序在运行时动态地分配和释放内存。堆管理器提供了一组函数或操作,用于分配和释放堆内存。堆内存可以被程序中的不同部分共享,并且可以在程序运行时动态地分配和释放。

(3)Keil工程在中文目录下,仿真退出会出错。

2.2、栈

(1)栈(Stack)是一种只能在一端进行插入和删除操作的数据结构,具有先进后出的特性。

(2)在RTOS中,每个任务都得有自己得栈。

(3)栈的功能。

  • 内存管理:在编程中,栈通常用于管理内存。当程序调用一个函数时,函数的参数、返回地址会被压入栈中,变量也会被存储在栈中。当函数返回时,这些值将从栈中弹出,释放内存。这种方式简化了内存管理,确保不会提前释放在占用状态下的内存空间。
  • 表达式求值:栈可以用于解决表达式求值问题。通常情况下,表达式中的操作符和操作数必须按照特定的规则进行计算。栈可以帮助记录操作符状态,并计算操作数。
  • 问题的回溯:栈也常用于问题的回溯,即在出现错误或面临问题时,通过回溯栈中的信息来了解问题发生的情况。
  • 操作系统多任务模式:栈是构建出操作系统多任务模式的基础,但在具体的实现中,需要用汇编代码来实现栈的切换。

3、FreeRTOS中的5种内存管理方法

        FreeRTOS中内存管理的接口函数为:pvPortMalloc 、vPortFree,对应于C库的malloc、free。文件在 FreeRTOS/Source/portable/MemMang 下,它也是放在 portable 目录下,表示你可以提供自己的函数。源码中默认提供了5个文件,对应内存管理的5种方法。

文件优点缺点
heap_1.c分配简单,时间确定只分配、不回收
heap_2.c动态分配、最佳匹配碎片、时间不定
heap_3.c调用标准库函数速度慢、时间不定
heap_4.c相邻空闲内存可合并可解决碎片问题、时间不定
heap_5.c在heap_4基础上支持分隔的内存块可解决碎片问题、时间不定

参考内容:《掌握FreeRTOS实时内核-实操教程》

3.1、Heap_1

(1)Heap_1只实现了pvPortMalloc,没有实现vPortFree。如果程序不需要删除内核对象,那么可以使用heap_1。

  • 实现最简单,没有碎片问题。
  • 一些要求非常严格的系统里,不允许使用动态内存,就可以使用heap_1。

(2)它的实现原理很简单,首先定义一个大数组,然后,对于pvPortMalloc调用时,从数组中分配空间。

/*为堆分配内存*/
##if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/*应用程序的作者已经定义了用于RTOS堆的数组——可能是为了把它放在一个特殊的段或地址中*/
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
##else
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
##endif /*配置应用程序分配堆*/

(3)FreeRTOS在创建任务时,需要2个内核对象:task control block(TCB)、stack。使用heap_1时,内存分配过程如下图所示:

  • A:创建任务之前整个数组都是空闲的。
  • B:创建第1个任务之后,蓝色区域被分配出去了。
  • C:创建3个任务之后的数组使用情况。

3.2、Heap_2

(1)Heap_2之所以还保留,只是为了兼容以前的代码。新设计中不再推荐使用Heap_2。建议使用Heap_4来替代Heap_2,更加高效。

(2)Heap_2也是在数组上分配内存,跟Heap_1不一样的地方在于:

  • Heap_2使用最佳匹配算法(best fit)来分配内存
  • 它支持vPortFree

(3)最佳匹配算法:

  • 假设heap有3块空闲内存:5字节、25字节、100字节。
  • pvPortMalloc想申请20字节。
  • 找出最小的、能满足pvPortMalloc的内存:25字节。
  • 把它划分为20字节、5字节。
  • 返回这20字节的地址,剩下的5字节仍然是空闲状态,留给后续的pvPortMalloc使用。

(4)与Heap_4相比,Heap_2不会合并相邻的空闲内存,所以Heap_2会导致严重的"碎片化"问题。
但是,如果申请、分配内存时大小总是相同的,这类场景下Heap_2没有碎片化的问题。所以它适合这种场景:频繁地创建、删除任务,但是任务的栈大小都是相同的(创建任务时,需要分配TCB和栈,任务的TCB大小总是一样的)。
(5)虽然不再推荐使用heap_2,但是它的效率还是远高于malloc、free。

(6)使用heap_2时,内存分配过程如下图所示:

  • A:创建了3个任务。
  • B:删除了一个任务,空闲内存有3部分:顶层的、被删除任务的TCB空间、被删除任务的Stack空间 。
  • C:创建了一个新任务,因为TCB、栈大小跟前面被删除任务的TCB、栈大小一致,所以刚好分配到原来的内存。

3.3、Heap_3

(1)Heap_3使用标准C库里的malloc、free函数,所以堆大小由链接器的配置决定,配置项configTOTAL_HEAP_SIZE不再起作用。
(2)C库里的malloc、free函数并非线程安全的,Heap_3中先暂停FreeRTOS的调度器,再去调用这些函数,使用这种方法实现了线程安全。

3.4、Heap_4

(1)跟Heap_1、Heap_2一样,Heap_4也是使用大数组来分配内存。Heap_4使用首次适应算法(first fit)来分配内存。它还会把相邻的空闲内存合并为一个更大的空闲内存,这有助于较少内存的碎片问题。

(2)首次适应算法:

  • 假设堆中有3块空闲内存:5字节、200字节、100字节。
  • pvPortMalloc想申请20字节。
  • 找出第1个能满足pvPortMalloc的内存:200字节。
  • 把它划分为20字节、180字节。
  • 返回这20字节的地址,剩下的180字节仍然是空闲状态,留给后续的pvPortMalloc使用。

(3)Heap_4会把相邻空闲内存合并为一个大的空闲内存,可以减少内存的碎片化问题。适用于这种场景:频繁地分配、释放不同大小的内存。

(4)Heap_4执行的时间是不确定的,但是它的效率高于标准库的malloc、free。

(5)Heap_4的使用过程举例如下:

  • A:创建了3个任务。
  • B:删除了一个任务,空闲内存有2部分:顶层的空闲内存,被删除任务的TCB空间、被删除任务的Stack空间合并起来的内存。
  • C:分配了一个Queue,从第1个空闲块中分配空间。
  • D:分配了一个User数据,从Queue之后的空闲块中分配。
  • E:释放的Queue,User前后都有一块空闲内存。
  • F:释放了User数据,User前后的内存、User本身占据的内存,合并为一个大的空闲内存。

3.5、Heap_5

(1)Heap_5分配内存、释放内存的算法跟Heap_4是一样的。相比于Heap_4,Heap_5并不局限于管理一个大数组:它可以管理多块、分隔开的内存。

(2)在嵌入式系统中,内存的地址可能并不连续,这种场景下可以使用Heap_5。

(3)既然内存时分隔开的,那么就需要进行初始化:确定这些内存块在哪、多大:

  • 在使用pvPortMalloc之前,必须先指定内存块的信息。
  • 使用vPortDefineHeapRegions来指定这些信息。

(4)怎么指定一块内存?使用如下结构体:

typedef struct HeapRegion
{uint8_t * pucStartAddress; // 起始地址size_t xSizeInBytes;       // 大小
} HeapRegion_t;

(5)怎么指定多块内存?使用一个HeapRegion_t数组,在这个数组中,低地址在前、高地址在后。比如:

HeapRegion_t xHeapRegions[] =
{{ ( uint8_t * ) 0x80000000UL, 0x10000 }, // 起始地址0x80000000,大小0x10000{ ( uint8_t * ) 0x90000000UL, 0xa0000 }, // 起始地址0x90000000,大小0xa0000{ NULL, 0 } // 表示数组结束
};

(6)vPortDefineHeapRegions函数原型如下,把xHeapRegions数组传给vPortDefineHeapRegions函数,即可初始化Heap_5。

void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions );

4、Heap相关的函数

4.1、pvPortMalloc/vPortFree

(1)函数原型:

void * pvPortMalloc( size_t xWantedSize );
void vPortFree( void * pv );

(2)作用:分配内存、释放内存。
(3)如果分配内存不成功,则返回值为NULL。

4.2、xPortGetFreeHeapSize

(1)函数原型:

size_t xPortGetFreeHeapSize( void );

(2)当前还有多少空闲内存,这函数可以用来优化内存的使用情况。比如当所有内核对象都分配好后,执行此函数返回2000,那么configTOTAL_HEAP_SIZE就可减小2000。
注意:在heap_3中无法使用。

4.3、xPortGetMinimumEverFreeHeapSize

(1)函数原型:

size_t xPortGetMinimumEverFreeHeapSize( void );

(2)返回:程序运行过程中,空闲内存容量的最小值。
(3)注意:只有heap_4、heap_5支持此函数。

4.4、malloc失败的钩子函数

(1)在pvPortMalloc函数内部:

void * pvPortMalloc( size_t xWantedSize )vPortDefineHeapRegions
{......#if ( configUSE_MALLOC_FAILED_HOOK == 1 ){if( pvReturn == NULL ){extern void vApplicationMallocFailedHook( void );vApplicationMallocFailedHook();}}#endifreturn pvReturn;
}

(2)所以,如果想使用这个钩子函数:

  • 在FreeRTOSConfig.h中,把configUSE_MALLOC_FAILED_HOOK定义为1。
  • 提供vApplicationMallocFailedHook函数。
  • pvPortMalloc失败时,才会调用此函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/97252.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ATF(TF-A)安全通告 TFV-5 (CVE-2017-15031)

安全之安全(security)博客目录导读 ATF(TF-A)安全通告汇总 目录 一、ATF(TF-A)安全通告 TFV-5 (CVE-2017-15031) 二、CVE-2017-15031 一、ATF(TF-A)安全通告 TFV-5 (CVE-2017-15031) Title 未初始化或保存/恢复PMCR_EL0可能会泄露安全世界的时间信息 CVE ID CVE-2017-1503…

亿级短视频,如何架构?

说在前面 在尼恩的(50)读者社群中,经常指导大家面试架构,拿高端offer。 前几天,指导一个年薪100W小伙伴,拿到字节面试邀请。 遇到一个 非常、非常高频的一个面试题,但是很不好回答&#xff0…

从外部访问K8s中Pod的五种方式

hostNetwork、 hostPort、 NodePort、 LoadBalancer、 Ingress 暴露Pod与Service一样,因为Pod就是Service的backend 1、hostNetwork:true 这是一种直接定义 Pod 网络的方式。 如果在 Pod 中使用 hostNetwork:true 配置, pod 中运行的应用程序…

SpringBoot项目集成ElasticSearch服务

本文已收录于专栏 《中间件合集》 目录 版本介绍背景介绍优势说明集成过程1.引入依赖2.添加配置文件3.初始化 示例说明代码结果 总结提升 版本介绍 Spring boot的版本是: 2.3.12   ElasticSearch的版本是:7.6.2 背景介绍 在我们的项目中经常会遇到对于…

java面试基础 -- ArrayList 和 LinkedList有什么区别, ArrayList和Vector呢?

目录 基本介绍 有什么不同?? ArrayList的扩容机制 ArrayLIst的基本使用 ArrayList和Vector 基本介绍 还记得我们的java集合框架吗, 我们来复习一下, 如图: 可以看出来 ArrayList和LinkedList 都是具体类, 他们都是接口List的实现类. 但是他们底层的逻辑是不同的, 相信…

2023-8-18 区间和

题目链接&#xff1a;区间和 #include <iostream> #include <vector> #include <algorithm>using namespace std;typedef pair<int, int> PII;const int N 300010;int n, m; int a[N], s[N]; vector<int> alls; vector<PII> add, query…

移植PeerTalk开源库IOS的USB通信监听服务到QT生成的FFmpeg工程

1.添加生成的PeerTalk库 下图选中部分为FFmpeg依赖库 将USB通信服务的m与h文件添加到工程 因为OC文件使用了弱指针,所以要启用弱指针支持 因为FFmpeg拉流动用到本地网络,所以要在plist文件中启动本地网络使用 设置PeerTalk为嵌入模式 设置Runpath Search Paths为@executable_p…

【欧拉计划】3或5的倍数

题目链接&#xff1a;3或5的倍数 解法一&#xff1a;暴力枚举 C语言代码 #include<stdio.h> int main (){int sum 0;for(int i 0;i<1000;i){if(i%30 || i%50)sum i;}printf("%d\n",sum);return 0; } //运行结果&#xff1a;233168上面这个解法的时间复杂…

Linux 虚拟机Ubuntu22.04版本通过远程连接连接不上,输入ifconfig只能看到127.0.0.1的解决办法

之前给虚拟机配置静态IP之后&#xff0c;可以直接通过主机Vscode远程连接。但是前一段时间把主机的TCP/IPV4静态IP设置了一下之后&#xff0c;再连接虚拟机就连不上了&#xff0c;于是参考解决虚拟机不能上网ifconfig只显示127.0.0.1的问题&#xff0c;又可以连接上了&#xff…

Swing程序设计(1)概述及常用组件

文章目录 前言一、什么是GUI?二、Swing概述 1.Swing包2.Swing常用组件总结 前言 该文介绍了Java中Swing组件的概述&#xff0c;以及常用组件的介绍。Swing程序是关于开发软件界面的一种轻量级Java组件。那什么是Swing组件&#xff1f;弹出对话框&#xff0c;窗体&#xff0c;设…

ClickHouse AST is too big 报错问题处理记录

ClickHouse AST is too big 报错问题处理记录 问题描述问题分析解决方案1、修改系统配置2、修改业务逻辑 问题描述 项目中统计报表的查询出现 AST is too big 问题&#xff0c;报错信息如下&#xff1a; 问题分析 报错信息显示 AST is too big。 AST 表示查询语法树中的最大…

pycharm调整最大堆发挥最大

python程序运行时&#xff0c;怎么提高效率&#xff0c;设置pycharm最大堆过程如下&#xff1b; 一、进入设置pycharm最大堆&#xff1b; 二、进入设置pycharm最大堆&#xff1b; 如果8g设置为6g左右&#xff0c;占75%左右最佳

自动驾驶港口车辆故障及事故处理机制

1、传感器故障&#xff1a; &#xff08;1&#xff09;单一传感器数据异常处理。自动驾驶电动平板传感方案为冗余设置&#xff0c;有其他传感器能够覆盖故障传感器观测区域&#xff0c;感知/定位模块将数据异常情况发给到规划决策模块&#xff0c;由“大脑”向中控平台上报故障…

mac m1上系统内录内部声音的方法/无需安装Blackhole

总所周知&#xff0c;m1的mac不能录制桌面音频&#xff0c;obsstudio都不行。 最快的解决方法就是下载飞书&#xff1a; 登陆后新建直播/视频会议&#xff1a; 共享的时候选择下面的两个钩上去就好了

野火i.mx 6ull上手

目录 屏幕驱动打印信息 实现触摸屏校验 开发板连接WIFI 连接操作 申请路由器动态IP和ping网络通断 WiFi信息保存位置 常用wifi操作&#xff08;wpa_cli工具&#xff09; NFS网络文件系统共享 虚拟机安装NFS服务器 开发板安装NFS客户端 控制开发板 找出硬件设备所对…

n5173b是德科技keysight N5173B信号发生器

产品概述 是德科技/安捷伦N5173B EXG模拟信号发生器 当您需要平衡预算和性能时&#xff0c;是德科技N5173B EXG微波模拟信号发生器是经济高效的选择。它提供解决宽带滤波器、放大器、接收机等参数测试的基本信号。执行基本LO上变频或CW阻塞&#xff0c;低成本覆盖13、20、31.…

Python土力学与基础工程计算.PDF-螺旋板载荷试验

python 求解代码如下&#xff1a; 1. import numpy as np 2. 3. # 已知参数 4. p_a 100 # 标准压力&#xff0c; kPa 5. p np.array([25, 50, 100, 200) # 荷载&#xff0c; kPa 6. s np.array([2.88, 5.28, 9.50, 15.00) / 10 # 沉降量&#xff0c; cm 7. D 10 # 螺旋板直…

在Windows Server 2008上启用自动文件夹备份

要在Windows Server 2008上启用自动文件夹备份&#xff0c;您可以使用内置的Windows备份功能。下面是如何设置它的方法&#xff1a; 1. 点击“开始”按钮并选择“服务器管理器”&#xff0c;打开“服务器管理器”。 2. 在“服务器管理器”窗口中&#xff0c;单击左侧窗格中的“…

kafka-- kafka集群 架构模型职责分派讲解

一、 kafka集群 架构模型职责分派讲解 生产者将消息发送到相应的Topic&#xff0c;而消费者通过从Topic拉取消息来消费 Kafka奇数个节点消费者consumer会将消息拉去过来生产者producer会将消息发送出去数据管理 放在zookeeper

【C# 基础精讲】异步和同步的区别

异步&#xff08;Asynchronous&#xff09;和同步&#xff08;Synchronous&#xff09;是在编程中经常遇到的两种执行模式。它们涉及到程序中任务的执行方式以及对资源的管理方式。在本文中&#xff0c;我们将深入探讨异步和同步的区别、使用场景以及在 C# 中如何实现异步编程。…