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

FreeRTOS内存管理

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

  • 对于内核对象,可以使用时分配,不使用时释放
  • C语音的库函数不适应与FreeRTOS:
    • 实现过于复杂,占用空间大
    • 并非线程安全的
    • 运行不确定性:每次运算时间不确定
    • 内存碎片化
    • 不太编译器配置不同
    • 调试难

2. 堆栈

我们经常说的“堆栈”,是两种不同的东西

2.1. 堆

heap就是一块空闲的内存,通过malloc、free来管理

2.2. 栈

stack,函数调用时局部变量保存在栈中,当前的程序环境也保存在栈中,可以充堆中分配一块内存用于栈空间

3. FreeRTOS系统5种内存管理方法

文件在 FreeRTOS/Source/portable/MemMang 下,5个文件对应5中内存管理方法:
在这里插入图片描述

3.1. Heap_1

3.1.1. 特点

只实现了pvPortMalloc,没有实现vPortFree,如果程序中不需要删除内核对象,不需要释放内存,那么可以实现heap_1:

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

3.1.2. 实现原理

  • 定义一个大数组
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
* heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
  • 调用pvPortMalloc调用时,从数组中分配空间

注意:
内存申请时,需要字节对齐处理
–> 在有些处理器中,访问奇地址访问内存会报错

3.2. Heap_2

Heap_2 之所以还保留,只是为了兼容以前的代码。新的设计中,不再推进实现Heap_2。
Heap_2也是在数组上分配内存,和Heap_1不一样的地方在于:

  • heap_2使用最佳匹配算法来分配内存
  • 支持vPortFree

3.2.1. 数据结构

typedef struct A_BLOCK_LINK
{struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */size_t xBlockSize;                     /*<< The size of the free block. */
} BlockLink_t;

3.2.2. 内存结构

在这里插入图片描述

3.2.3. 最佳匹配算法:

  • 假设Heap有3个空闲块:5字节、25字节、100字节
  • pvPortMalloc想申请20个字节
  • 先找到最小的、能满足要求的内存:25字节
  • 把它分为20字节、5字节
    • 返回20字节的地址
    • 剩下的5字节仍是空闲状态,继续留给后续使用

与Heap_4相比,Heap_2不会合并相邻的空闲内存,所以Heap_2会导致严重的碎片化问题,但是如果申请、分配内存大小都相同的场景下,Heap_2就没有碎片化问题,所以它适合这些场景:频繁窗户删除任务、但任务的栈大小都是相同的。
虽然不再推荐使用Heap_2,但它的效率还是远高于malloc、free.

3.3. Heap_3

Heap_3 使用标准 C 库里的 malloc、 free 函数,C 库里的 malloc、 free 函数并非线程安全的, Heap_3 中先暂停 FreeRTOS 的调度器,再去调用这些函数,使用这种方法实现了线程安全。

3.4. Heap_4

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

3.4.1. 首次适应算法

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

Heap_4 会把相邻空闲内存合并为一个大的空闲内存,可以较少内存的碎片化问题。适用于这种场景:频繁地分配、释放不同大小的内存。
Heap_4 的使用过程举例如下:

  • A:创建了 3 个任务
  • B:删除了一个任务,空闲内存有 2 部分:
    • 顶层的
    • 被删除任务的 TCB 空间、被删除任务的 Stack 空间合并起来的
  • C:分配了一个 Queue,从第 1 个空闲块中分配空间
  • D:分配了一个 User 数据,从 Queue 之后的空闲块中分配
  • E:释放的 Queue, User 前后都有一块空闲内存
  • F:释放了 User 数据, User 前后的内存、 User 本身占据的内存, 合并为一个大的空闲内存
    在这里插入图片描述
    Heap_4 执行的时间是不确定的,但是它的效率高于标准库的 malloc、 free。

3.5. Heap_5

Heap_5 分配内存、释放内存的算法跟 Heap_4 是一样的。
相比于 Heap_4, Heap_5 并不局限于管理一个大数组:它可以管理多块、分隔开的内存。
在嵌入式系统中,内存的地址可能并不连续,这种场景下可以使用 Heap_5。
既然内存时分隔开的,那么就需要进行初始化:确定这些内存块在哪、多大:

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

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

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

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

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

vPortDefineHeapRegions 函数原型如下:

void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions );

把 xHeapRegions 数组传给 vPortDefineHeapRegions 函数,即可初始化 Heap_5。

4. Heap接口

4.1. pvPortMalloc/vPortFree

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

4.2. xPortGetFreeHeapSize

size_t xPortGetFreeHeapSize( void );

只有 heap_4、 heap_5 支持此函数。

4.3. xPortGetMinimumEverFreeHeapSize

size_t xPortGetMinimumEverFreeHeapSize( void );

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

4.4. malloc 失败的钩子函数

void * pvPortMalloc( size_t xWantedSize )vPortDefineHeapRegions

相关文章:

FreeRTOS内存管理

1. 为什么要自己实现内存管理 对于内核对象&#xff0c;可以使用时分配&#xff0c;不使用时释放C语音的库函数不适应与FreeRTOS: 实现过于复杂&#xff0c;占用空间大并非线程安全的运行不确定性&#xff1a;每次运算时间不确定内存碎片化不太编译器配置不同调试难 2. 堆栈…...

利用服务工作线程serviceWorker缓存静态文件css,html,js,图片等的方法,以及更新和删除及版本控制

Service Worker 是一种运行在浏览器背后的独立线程&#xff0c;可以用来处理推送通知、后台同步、缓存等任务。以下是使用 Service Worker 来缓存图片的一个基本示例&#xff1a; 1、注册 Service Worker: 首先&#xff0c;你需要在你的 JavaScript 文件中注册 Service Worker。…...

MuMu模拟器安卓12安装Xposed 框架

MuMu模拟器安卓12安装Xposed 框架 当开启代理后,客户端会对代理服务器证书与自身内置证书展开检测,只要检测出两者存在不一致的情况,客户端就会拒绝连接。正是这个原因,才致使我们既没有网络,又抓不到数据包。 解决方式: 通过xposed框架和trustmealready禁掉app里面校验…...

高级数据结构——hash表与布隆过滤器

文章目录 hash表与布隆过滤器1. hash函数2. 选择hash函数3. 散列冲突3.1 负载因子3.2 冲突解决3. STL中的散列表 4. 布隆过滤器4.1 背景1. 应用场景2. 常见的处理场景&#xff1a; 4.2 布隆过滤器构成4.3 原理4.4 应用分析4.5 要点 5. 分布式一致性hash5.1 缓存失效问题 6. 大数…...

【网络】什么是交换机?switch

交换机&#xff08;Switch&#xff09;意为“开关”&#xff0c;是一种用于电&#xff08;光&#xff09;信号转发的网络设备。以下是关于交换机的详细解释&#xff1a; 一、交换机的基本定义 功能&#xff1a;交换机能为接入交换机的任意两个网络节点提供独享的电信号通路&am…...

软件测试 —— 自动化基础

目录 前言 一、Web 自动化测试 1.什么是 Web 自动化测试 2.驱动 3.安装驱动管理 二、Selenium 1.简单 web 自动化测试示例 2.工作原理 三、元素定位 1.cssSelector 2.XPath 四、操作测试对象 1.点击/提交对象 2.模拟按键输入 3.清除文本内容 4.获取文本信息 5.…...

深入解析 OpenHarmony 构建系统-4-OHOSLoader类

在OpenHarmony操作系统构建过程中&#xff0c;OHOSLoader类扮演着至关重要的角色。这个类负责加载和解析构建配置&#xff0c;生成必要的构建文件&#xff0c;并确保构建过程的顺利进行。本文将深入分析OHOSLoader类的实现细节&#xff0c;揭示其如何管理构建配置&#xff0c;并…...

【Android、IOS、Flutter、鸿蒙、ReactNative 】实现 MVP 架构

Android Studio 版本 Android Java MVP 模式 参考 模型层 model public class User {private String email;private String password;public User(String email, String password) {this.email = email;this.password = password;}public String getEmail() {return email;}…...

排序算法(基础)大全

一、排序算法的作用&#xff1a; 排序算法的主要作用是将一组数据按照特定的顺序进行排列&#xff0c;使得数据更加有序和有组织。 1. 查找效率&#xff1a;通过将数据进行排序&#xff0c;可以提高查找算法的效率。在有序的数据中&#xff0c;可以使用更加高效的查找算法&…...

Pytest从入门到精通

一、pytest单元测试框架 (1)什么是单元测试框架 单元测试是指在软件开发当中,针对软件的最小单位(函数,方法)进行正确性的检查测试。 (2)单元测试框架 java : junit和testng python : unittest和pytest (3)单元测试框架主要做什么? 1.测试发现:从多个文件里面去找到我们测试…...

《C++ 实现生成多个弹窗程序》

《C 实现生成多个弹窗程序》 在 C 编程中&#xff0c;我们可以利用特定的系统函数来创建弹窗&#xff0c;实现向用户展示信息等功能。当需要生成多个弹窗时&#xff0c;我们可以通过循环结构等方式来达成这一目的。 一、所需头文件及函数介绍 在 Windows 操作系统环境下&#…...

react 中 useRef Hook 作用

useRef是一个非常实用的钩子函数 一、访问和操作 DOM 元素 1. 获取 DOM 元素引用 1.1 基本原理 通过 useRef 我们可以直接操作 DOM 元素 1.2 代码示例 import React, { useRef, useEffect } from "react";const InputFocusComponent () > {const inputRef …...

Scala-键盘输入(StdIn)-用法详解

Scala 在 Scala 中&#xff0c;进行 键盘输入 主要通过 scala.io.StdIn 包来实现。 StdIn 提供了几个方法&#xff0c;用于从用户的键盘输入中读取不同类型的数据&#xff0c;如字符串、整数、浮点数等。 常用的输入方法有 readLine()、readInt()、readDouble()、readShort(…...

力扣(LeetCode)283. 移动零(Java)

White graces&#xff1a;个人主页 &#x1f649;专栏推荐:Java入门知识&#x1f649; &#x1f439;今日诗词:雾失楼台&#xff0c;月迷津渡&#x1f439; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主&#x1f64f; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主…...

ESP32C3单片机使用笔记---烧录MicroPython

使用MicroPython在ESP32C3单片机上编程&#xff0c;首先需要将MicroPython运行环境烧录到ESP32C3的Flash中去&#xff0c;步骤如下&#xff1a; 1.下载esptool烧录工具&#xff0c;下载地址&#xff1a; https://github.com/espressif/esptool 直接使用git clone git clone…...

Matter1.4重磅来袭,智能家居进入“互联”新纪元

近日&#xff0c;连接标准联盟&#xff08;CSA&#xff09;正式宣布推出最新的Matter1.4标准版本&#xff0c;并更新了一系列“史诗级”的增强功能&#xff0c;旨在提升现有智能家居之间的互操作性与兼容性&#xff0c;为智能家居用户带来更流畅的使用体验。 华普微&#xff0c…...

tdengine学习笔记

官方文档&#xff1a;用 Docker 快速体验 TDengine | TDengine 文档 | 涛思数据 整体架构 TDENGINE是分布式&#xff0c;高可靠&#xff0c;支持水平扩展的架构设计 TDengine分布式架构的逻辑结构图如下 一个完整的 TDengine 系统是运行在一到多个物理节点上的&#xff0c;包含…...

机器学习-36-对ML的思考之机器学习研究的初衷及科学研究的期望

文章目录 1 机器学习最初的样子1.1 知识工程诞生(专家系统)1.2 知识工程高潮期1.3 专家系统的瓶颈(知识获取)1.4 机器学习研究的初衷2 科学研究对机器学习的期望2.1 面向科学研究的机器学习轮廓2.2 机器学习及其应用研讨会2.3 智能信息处理系列研讨会2.4 机器学习对科学研究的重…...

Linux 进程信号的产生

目录 0.前言 1. 通过终端按键产生信号 1.1 CtrlC&#xff1a;发送 SIGINT 信号 1.2 Ctrl\&#xff1a;发送 SIGQUIT 信号 1.3 CtrlZ&#xff1a;发送 SIGTSTP 信号 2.调用系统命令向进程发信号 3.使用函数产生信号 3.1 kill 函数 3.2 raise 函数 3.3 abort 函数 4.由软件条件产…...

CentOS8 在MySQL8.0 实现半同步复制

#原理 MySQL默认是异步的,不要求必须全部同步到从节点才返回成功结果; 同步复制: 用户发请求到代理, 代理收到请求后写/更新数据库写入到二进制日志bin_log, 然后必须等数据发到所有的从节点, 从节点全部收到数据后, 主节点才返回给客户端的成功结果。 弊端&#xff1a; 客…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...

倒装芯片凸点成型工艺

UBM&#xff08;Under Bump Metallization&#xff09;与Bump&#xff08;焊球&#xff09;形成工艺流程。我们可以将整张流程图分为三大阶段来理解&#xff1a; &#x1f527; 一、UBM&#xff08;Under Bump Metallization&#xff09;工艺流程&#xff08;黄色区域&#xff…...

Tauri2学习笔记

教程地址&#xff1a;https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引&#xff1a;https://tauri.app/zh-cn/start/ 目前Tauri2的教程视频不多&#xff0c;我按照Tauri1的教程来学习&…...

五、jmeter脚本参数化

目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...

使用homeassistant 插件将tasmota 接入到米家

我写一个一个 将本地tasmoat的的设备同通过ha集成到小爱同学的功能&#xff0c;利用了巴法接入小爱的功能&#xff0c;将本地mqtt转发给巴法以实现小爱控制的功能&#xff0c;前提条件。1需要tasmota 设备&#xff0c; 2.在本地搭建了mqtt服务可&#xff0c; 3.搭建了ha 4.在h…...