当前位置: 首页 > news >正文

FreeRTOS的内存管理(选择heap4.c文件的理由)

       

目录

1. 了解FreeRTOS内存管理

2. 了解内存碎片

3.了解各个heap.c的内存分配方法

1.heap1.c

2.heap2.c

3.heap3.c

4.heap4.c

5.heap5.c

总结:


      内存管理是一个系统基本组成部分,FreeRTOS 中大量使用到了内存管理,比如创建任务、信号量、队列等会自动从堆中申请内存,用户应用层代码也可以 FreeRTOS 提供的内存管理函数来申请和释放内存,他们是heap1~5.c,下面就粗略的讲解一下他们的特性。

1. 了解FreeRTOS内存管理

      FreeRTOS创建任务、队列、信号量等的时候有两种方法,一种是动态的申请所需的RAM 一种是由用户自行定义所需的 RAM,这种方法也叫静态方法,使用静态方法的函数一般以 Static”结尾,比如任务创建函数 xTaskCreateStatic(),使用此函数创建任务的时候需要由用户定义任务堆栈,本章我们不讨论这种静态方法。

     使用动态内存管理的时候 FreeRTOS  内核在创建任务、队列、信号量的时候会动态的申请RAM。标准 C 库中的 malloc() free()也可以实现动态内存管理,但是如下原因限制了其使用:

● 在小型的嵌入式系统中效率不高。

● 会占用很多的代码空间。

● 它们不是线程安全的。

● 具有不确定性,每次执行的时间不同。

● 会导致内存碎片。

● 使链接器的配置变得复杂。

       不同的嵌入式系统对于内存分配和时间要求不同,因此一个内存分配算法可以作为系统的可选选项。FreeRTOS 将内存分配作为移植层的一部分,这样 FreeRTOS 使用者就可以使用自己的合适的内存分配方法。

      当内核需要 RAM 的时候可以使用 pvPortMalloc()来替代 malloc()申请内存,不使用内存的时候可以使用 vPortFree()函数来替代 free()函数释放内存。函数 pvPortMalloc()vPortFree()与函  malloc() free()的函数原型类似。

      FreeRTOS 提供了 5 种内存分配方法,FreeRTOS 使用者可以其中的某一个方法,或者自己的内存分配方法。这 5 种方法是 5 个文件,分别为:heap_ 1.c heap_2.c heap_3.c heap_4.c  heap_5.c。这 5 个文件再 FreeRTOS 源码中,路径:FreeRTOS->Source->portable->MemMang  后面会详细讲解这 5 种方法有何区别。

2. 了解内存碎片

在看 FreeRTOS  的内存分配方法之前我们先来看一下什么叫做内存碎片,看名字就知道是 小块的、碎片化的内存。那么内存碎片是怎么来的呢?内存碎片是伴随着内存申请和释放而来 的,如图所示。

(1)、此时内存堆还没有经过任何操作,为全新的。

(2)、此时经过第一次内存分配,一共分出去了 4 块内存块,大小分别为 80B80B 10B  100B

(3)、有些应用使用完内存,进行了释放,从左往右第一个 80B 和后面的 10B 这两个内存块 就是释放的内存。如果此时有个应用需要 50B 的内存,那么它可以从两个地方来获取到,一个 是最前面的还没被分配过的剩余内存块,另一个就是刚刚释放出来的 80B 的内存块。但是很明 显,刚刚释放出来的这个 10B 的内存块就没法用了,除非此时有另外一个应用所需要的内存小  10B

(4)、经过很多次的申请和释放以后,内存块被不断的分割、最终导致大量很小的内存块! 也就是图中 80B  50B 这两个内存块之间的小内存块,这些内存块由于太小导致大多数应用无 法使用,这些没法使用的内存块就沦为了内存碎片!

内存碎片是内存管理算法重点解决的一个问题,否则的话会导致实际可用的内存越来越少, 最终应用程序因为分配不到合适的内存而奔溃!FreeRTOS   heap_4.c 就给我们提供了一个解 决内存碎片的方法,那就是将内存碎片进行合并组成一个新的可用的大内存块。

3.了解各个heap.c的内存分配方法

1.heap1.c

heap_ 1 实现起来就是当需要 RAM  的时候就从一个大数组(内存堆)中分一小块出来,大数(内存堆)的容量为 configTOTAL_HEAP_SIZE,上面已经说了。使用函数xPortGetFreeHeapSize() 可以获取内存堆中剩余内存大小。

注意!!!heap1.c没有内存释放函数!

heap_1 的特性如下:

1、适用于那些一旦创建好任务、信号量和队列就再也不会删除的应用,实际上大多数的 FreeRTOS 应用都是这样的。

2、具有可确定性(执行所花费的时间大多数都是一样的),而且不会导致内存碎片。

3、代码实现和内存分配过程都非常简单,内存是从一个静态数组中分配到的,也就是适合 于那些不需要动态内存分配的应用。

2.heap2.c

heap_2 提供了一个更好的分配算法,不像heap_ 1 那样,heap_2供了内存释放函数heap_2 不会把释放的内存块合并成一个大块,这样有一个缺点,随着你不断的申请内存,内存堆就会被分为很多个大小不一的内存(),也就是会导致内存碎片!heap_4  提供了空闲内存块合并的功能。

heap_2 的特性如下:

1、可以使用在那些可能会重复的删除任务、队列、信号量等的应用中,要注意有内存碎片产生!

2、如果分配和释放的内存 n 大小是随机的,那么就要慎重使用了,比如下面的示例:

      ●  如果一个应用动态的创建和删除任务,而且任务需要分配的堆栈大小都是一样的,那么heap_2 就非常合适。如果任务所需的堆栈大小每次都是不同,那么 heap_2  不适合了,因为这样会导致内存碎片产生,最终导致任务分配不到合适的堆栈!不heap_4 就很适合这种场景了。

      ●  如果一个应用中所使用的队列存储区域每次都不同,那么 heap_2 就不适合了,和上面一样,此时可以使用 heap_4

     ●  应用需要调用 pvPortMalloc() vPortFree()来申请和释放内存,而不是通过其他FreeRTOS的其他 API 函数来间接的调用,这种情况下 heap_2 不适合。

3、如果应用中的任务、队列、信号量和互斥信号量具有不可预料性(如所需的内存大小不能确定,每次所需的内存都不相同,或者说大多数情况下所需的内存都是不同的)的话可能会导致内存碎片。虽然这是小概率事件,但是还是要引起我们的注意!

4、具有不可确定性,但是也远比标准 C 中的 malloc() free()效率高!

      heap_2 基本上可以适用于大多数的需要动态分配内存的工程中,而 heap_4 更是具有将内存 碎片合并成一个大的空闲内存块(就是内存碎片回收)功能。

3.heap3.c

这个分配方法是对标准 C 中的函数 malloc() free()的简单封装,FreeRTOS 对这两个函数做了线程保护。

heap_3 的特性如下:

1、需要编译器提供一个内存堆,编译器库要提供 malloc() free()函数。比如使用 STM32 的话可以通过修改启动文件中的 Heap_Size 来修改内存堆的大小,如图所示

2、具有不确定性

3 、可能会增加代码量。

注意,在 heap_3  configTOTAL_HEAP_SIZE 是没用的!

4.heap4.c

heap_4提供了一个最优的匹配算法,不heap_2heap_4会将内存碎片合并成一个大的可用内存块,它提供了内存块合并算法。内存堆为ucHeap[],大小同样为 configTOTAL_HEAP_SIZE 可以通过函数 xPortGetFreeHeapSize()来获取剩余的内存大小。

heap_4 特性如下:

1 、可以用在那些需要重复创建和删除任务、队列、信号量和互斥信号量等的应用中。

2、不会像 heap_2 那样产生严重的内存碎片,即使分配的内存大小是随机的。

3、具有不确定性,但是远比 C 标准库中的 malloc() free()效率高。

heap_4 非常适合于那些需要直接调用函数 pvPortMalloc()vPortFree()来申请和释放内存的应用,注意,我们移植 FreeRTOS 的时候就选择的 heap_4

heap_4 也使用链表结构来管理空闲内存块,链表结构体与 heap_2 一样。heap_4 也定义了两个局部静态变量 xStart  pxEnd 来表示链表头和尾,其中 pxEnd 是指向 BlockLink_t 的指针。

5.heap5.c

       heap_5 使用了和 heap_4 相同的合并算法,内存管理实现起来基本相同,但是heap_5允许内存堆跨越多个不连续的内存段。比如STM32 的内部 RAM 可以作为内存堆,但是STM32RAM比较小,遇到那些需要大容量 RAM 的应用就不行了,如音视频处理。不过 STM32  以外接 SRAM  甚至大容量的 SDRAM,如果使用 heap_4  的话你就只能在内部 RAM  和外部 SRAM SDRAM 之间二选一了,使用 heap_5 的话就不存在这个问题,两个都可以一起作为内存堆来用。

       如果使用 heap_5 的话,在调用 API 函数之前需要先调用函数vPortDefineHeapRegions()对内存堆做初始化处理,在vPortDefineHeapRegions()未执行完之前禁止调用任何可能会调用pvPortMalloc() API 函数!比如创建任务、信号量、队列等函数。函数vPortDefineHeapRegions() 只有一个参数,参数是一个 HeapRegion_t 类型的数组,HeapRegion 为一个结构体,此结构体在 portable.h 中有定义,这里就不例出例子了。    

      注意,数组中成员顺序按照地址从低到高的顺序排列,而且最后一个成员必须使用NULLheap_5 允许内存堆不连续,说白了就是允许有多个内存堆。在 heap_2  heap_4 中只有一个内 存堆,初始化的时候只也只需要处理一个内存堆。 heap_5 有多个内存堆,这些内存堆会被连接 在一起,和空闲内存块链表类似,这个处理过程由函数 vPortDefineHeapRegions()完成。

      使用heap_5  的时候在一开始就应该先调用函数 vPortDefineHeapRegions()完成内存堆的初始化!然后才能创建任务、信号量这些东西。

//使用heap_5 的时候在开启任务调度器、创建任务、创建信号量之前一定要先

//调用函数 vPortDefineHeapRegions()初始化内存堆!

vPortDefineHeapRegions((const HeapRegion_t *)xHeapRegions);

      heap_5 的内存申请和释放函数和 heap_4 基本一样,这里就不详细讲解了,大家可以对照着前面 heap_4 的相关内容来自行分析。

     至此,FreeRTOS 官方提供的 5 种内存分配方法已经讲完了heap_1 最简单,但是只能申请 内存,不能释放。heap_2 提供了内存释放函数,用户代码也可以直接调用函数 pvPortMalloc() vPortFree()来申请和释放内存,但是 heap_2 会导致内存碎片的产生!heap_3 对标准 C 库中的 函数 malloc() free()的简单封装,并且提供了线程保护。heap_4 相对与 heap_2 提供了内存合 并功能,可以降低内存碎片的产生,我们移植 FreeRTOS 时候就选择了 heap_4 heap_5 基本 上和 heap_4 一样,只是 heap_5 支持内存堆使用不连续的内存块。

总结:

       heap.c虽然在使用的时候可以傻瓜式的直接无脑使用heap.4,但从heap1到heap5,我们可以看到FreeRTOS对于更加有秀的内存分配方法所作出的努力,从heap1只能固定格式分配、没提供内存删除函数、到heap4提供内存合并算法,就像牙牙学语的婴儿逐步成长成为了巨人,越来越强大。

     到这里,FreeRTOS的学习也告一段落,FreeRTOS中的队列、信号量、列表、软件定时器、配置API函数、事件组、任务通知、延迟函数、空闲函数、优先级希望大家有学会并有所收获,下面就是做实际的项目边学边练,希望大家能够将FreeRTOS学到手!

相关文章:

FreeRTOS的内存管理(选择heap4.c文件的理由)

目录 1. 了解FreeRTOS内存管理 2. 了解内存碎片 3.了解各个heap.c的内存分配方法 1.heap1.c 2.heap2.c 3.heap3.c 4.heap4.c 5.heap5.c 总结: 内存管理是一个系统基本组成部分,FreeRTOS 中大量使用到了内存管理,比如创建任务、信号量…...

SQL-leetcode-183. 从不订购的客户

183. 从不订购的客户 Customers 表: -------------------- | Column Name | Type | -------------------- | id | int | | name | varchar | -------------------- 在 SQL 中,id 是该表的主键。 该表的每一行都表示客户的 ID 和名称。 Orders 表&#…...

苹果系统MacOS下ObjectC建立的App程序访问opencv加载图片程序

前言 苹果系统下使用opencv感觉还是有些不太方便,总是感觉有点受到限制。本博客描述的是在MacOS下建立App程序然后调用opencv显示图片时出现的一些问题并最后解决的一个过程。 一、程序的建立 选择程序的类型: 选择界面模式和编程语言: 其余…...

《代码随想录》Day21打卡!

写在前面:祝大家新年快乐!!!2025年快乐,2024年拜拜~~~ 《代码随想录》二叉树:修剪二叉搜索树 本题的完整题目如下: 本题的完整思路如下: 1.本题使用递归进行求解,所以分…...

Dell服务器升级ubuntu 22.04失败解决

ubuntu系统原版本20.04,服务器dell T40. 执行apt update后,再执行apt upgrade。 apt update执行成功,但apt upgrade执行中断,提示如下: Checking package manager Reading package lists... Done Building dependen…...

构建全志 T113 Tina SDK

1、环境配置: 准备一个 Ubuntu 系统,可以是 WSL,虚拟机等,建议版本是 20.04。 1.1、安装必要的软件 进入系统后,输入下方命令安装需要的工具 : sudo apt update -y sudo apt full-upgrade -y sudo apt i…...

(推荐)【通用业务分发架构】1.业务分发 2.rpc调用 3.Event事件系统

一.Reflections和SpringUtil完成扫描包的(反射缓存) 二.id与class的映射泛型上下文(玩家是否登录,rpc调用SeqId,class类名)反射调用 1.netty层的 AccountMsgParam // 登录前 OnlineMsgParam // 登录后 SceneMsgParam // 发到场景层的 2.跨进程rpc调用的…...

最近的一些事情

正义不会缺席 这家公司违法辞退不给工资乱开离职证明。严重影响个人发展。 今天终于收到法院的判决书。 警醒自身发展与社会之间密切交流,敲响警钟。 虽然最终得到的法院的支持,但过程举步维艰。 这其中的过程,也让我对律师、法院和中国…...

CP AUTOSAR标准之FlexRayDriver(AUTOSAR_SWS_FlexRayDriver)(更新中……)

1 简介和功能概述 FlexRay驱动程序(Fr)抽象了特定FlexRay通信控制器(CC)的硬件相关实现细节。本规范主要依赖于符合FlexRay规范[13]的FlexRay CC。此外,本规范还支持符合FlexRay规范[14]的旧版FlexRay控制器。本SWS中因支持的FlexRay规范不同而导致的不同行为在适用的情况下以…...

Cesium 实战 27 - 三维视频融合(视频投影)

Cesium 实战 27 - 三维视频融合(视频投影) 核心代码完整代码在线示例在 Cesium 中有几种展示视频的方式,比如墙体使用视频材质,还有地面多边形使用视频材质,都可以实现视频功能。 但是随着摄像头和无人机的流行,需要视频和场景深度融合,简单的实现方式则不能满足需求。…...

GraphRAG实践:docker部署neo4j

概述 随着图数据库(Graph Database)的流行,越来越多的应用场景开始采用图数据库来处理复杂的关系数据。Neo4j作为领先的图数据库之一,提供了强大的图形查询语言Cypher、高效的存储结构和丰富的生态系统,使得它成为开发…...

常用的数据库类型都有哪些

在Java开发和信息系统架构中,数据库扮演着存储和管理数据的关键角色。数据库种类繁多,各有特色,适用于不同的应用场景。 1. 关系型数据库(RDBMS): • 关系型数据库是最为人熟知的数据库类型,数据…...

swiftui开发页面加载发送请求初始化@State变量

在SwiftUI中,你不能直接在init中更新State变量,因为State是由SwiftUI框架管理的,初始化时不允许直接修改。所以需要在onAppear发送请求然后修改State状态。 在SwiftUI中,如果希望在页面加载时立即发送网络请求,可以使…...

Ribbon和Eureka的集成

Ribbon和Eureka的集成是Spring Cloud Netflix生态系统的一部分,通常用于微服务架构中,以实现客户端负载均衡和服务发现。以下是更详细的集成步骤: 1. 引入依赖 在你的Spring Boot项目的pom.xml文件中添加Eureka客户端和Ribbon的依赖&#x…...

关于UE加载osgb数据的研究(一)

最近关于倾斜数据在UE中加载显示的问题,直接转换格式本地加载的方式避免了数据延迟加载、缓存加载,动态刷新等问题,但是也暴露了突出的问题:常规的模型格式会丢失掉倾斜数据的lod,致使效果缺失。 故而需要深入研究一下UE加载osgb数据的方式方法。 首先,我们需得学习一下…...

探索数据之美,Plotly引领可视化新风尚

在数据如潮的今天,如何精准捕捉信息的脉搏,让数据说话?Plotly,这款强大的数据可视化工具,正以其卓越的性能和丰富的功能,成为数据分析师、科学家及工程师们的得力助手。 Plotly不仅仅是一个绘图库&#xf…...

List排序的方法

List 排序方法: 1. list 的 sort() package com.example.a; import java.util.ArrayList; import java.util.Comparator; import java.util.List; class User{private Integer score;private Integer age;public User(Integer score, Integer age){super();this.…...

BurstAttention:高效的分布式注意力计算框架

BurstAttention:高效的分布式注意力计算框架 在现代大型语言模型(LLMs)的应用中,提升注意力机制的计算效率已成为研究的热点。当前,提升计算效率主要有两种方法:一种是优化单设备的计算和存储能力&#xf…...

大数据治理:构建稳健的数据生态系统

引言 随着信息技术的迅猛发展,企业每天都在生成海量的数据。这些数据不仅来自传统的业务交易系统,还包括社交媒体、物联网设备、移动应用程序等多个渠道。大数据治理旨在确保组织能够有效地管理其拥有的所有数据资产,以支持决策制定、优化业…...

【图书介绍】几本适合当教材的大数据技术图书

《Spark SQL大数据分析快速上手》 《Spark SQL大数据分析快速上手(大数据技术丛书)》(迟殿委,王泽慧,黄茵茵)【摘要 书评 试读】- 京东图书 《Spark SQL大数据分析快速上手》内容基于Spark新版本展开,符合企业目前开…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

MySQL 主从同步异常处理

阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示&#xff…...

云原生周刊:k0s 成为 CNCF 沙箱项目

开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...

Spring AOP代理对象生成原理

代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...