当前位置: 首页 > 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; 客…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...