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

【FreeRTOS】内存管理

内存管理

  • FreeRTOS内存管理
    • 内存碎片
    • heap_1内存分配方法
    • heap_2内存分配方法
    • heap_3内存分配方法
    • heap_4内存分配方法(常用)
    • heap_5内存分配方法
    • 总结
    • 内存管理实验

FreeRTOS内存管理

FreeRTOS创建任务、队列、信号量等数据需要内存时,有两种内存创建方法:一时动态申请所需的RAM,二是静态申请所需RAM,一般使用静态创建内存的函数名结尾带有"Static"。

在标准C库中提供了malloc()和free()函数来实现动态内存管理,但由于部分原因限制使用:

  • 在小型的嵌入式系统中效率不高
  • 会占用很多的代码空间
  • 不是线程安全
  • 会导致内存碎片
  • 使链接器的配置变得复杂

因此FreeRTOS的内存管理方法中提供了pvPortMalloc()来替代malloc()申请内存,vPortFree()函数来替代free()释放内存。

FreeRTOS提供了5种内存分配方法,使用FreeRTOS时任选其一即可,分别是:heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c,这5个文件再FreeRTOS源码中,路径:FreeRTOS->Source->portable->MemMang中。

动态内存分配需要一个内存堆,在FreeRTOS中内存堆为ucHeap[],大小为configTOTAL_HEAP_SIZE。不管是哪种内存分配方法,它们的内存堆都为ucHeap[],而且大小都为configTOTAL_HEAP_SIZE,内存堆在文件heap_x.c(x为1-5)中定义,比如heap_1.c文件中有如下定义:

#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; //需要用户自行定义内存堆
#else
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; //编译器决定
#endif

宏configAPPLICATION_ALLOCATED_HEAP为1时由用户自行定义内存堆,否则有编译器决定,默认都是编译器决定。

内存碎片

内存堆在经过多次申请和释放后,会产生很多内存很小的内存块,这些内存卡地址不连续,无法重新申请使用,这种内存块就叫内存碎片。

heap_1内存分配方法

特性:

  1. 适用于一旦创建好任务、信号量和队列就不在删除的应用
  2. 具有可确定性(执行所华花费的时间大多数都是一样的),而且不会导致内存碎片(因为heap_1算法无法处理内存碎片)
  3. 代码实现和内存分配过程非常简单,内存是从一个静态数组中分配到的,也就是适合于不需要动态分配内存的应用

heap_1算法没有提供内存释放函数

heap_2内存分配方法

其实与heap_1算法差不多一致,唯一的区别就是多了内存释放函数,通过引入内存块的概念和一个链表结构,来实现内存释放,该链表结构包含当前内存块的大小和指向链表中下一个空闲内存块。

特性:

  1. 可以使用在需要重复申请释放内存的应用,但是会产生内存碎片
  2. 具有不可确定性,但远比标准C中的malloc()和free()效率高

heap_3内存分配方法

特性:

  1. 需要编译器提供一个内存堆,编译器库要提供malloc()和free()函数,比如使用STM32的话可以通过修改启动文件中的Heap_Size来修改内存堆的大小
  2. 具有不确定性
  3. 可能会增加代码量(因为内部其实是调用malloc和free)

heap_3其实就是对标准C库中的malloc和free进行了简单的封装,所以才需要编译器库提供两个函数,也才会导致代码量增加

heap_4内存分配方法(常用)

heap_4其实是在heap_2的基础上进一步优化,依然使用和heap_2一样的链表结构,并额外定义两个局部静态变量xStart和pxEnd来表示链表头和尾

特性:

  1. 可以用在需要重复申请释放内存的应用中
  2. 不会产生严重的内存碎片,即使分配的内存大小是随机的
  3. 具有不确定性,但远比标准C中的malloc()和free()效率高

heap_5内存分配方法

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

如果使用 heap_5 的话,在调用 API 函数之前需要先调用函数 vPortDefineHeapRegions ()来
对内存堆做初始化处理,在 vPortDefineHeapRegions()未执行完之前禁止调用任何可能会调用
pvPortMalloc()的 API 函数!

总结

heap_1最简单,但是只有内存申请函数,没有内存释放函数

heap_2在heap_1的基础上多了内存释放函数

heap_3只是对标准C库中的malloc和free进行封装,并提供了线程保护

heap_4在heap_2的基础上对内存碎片进行了处理

heap_5在heap_4的基础上实现对不连续内存堆的应用

内存管理实验

在做内存管理实验时,通过pvPortMalloc(30)申请了30个字节的内存空间,在申请前通过xPortGetFreeHeapSize()获取的剩余内存为7136,申请后发现变成了7096,说明申请了40个字节的内存,但实际上只申请了30,这是因为除开所申请的30字节内存外,还要加上结构体BlockLink_t的大小然后做8字节对齐后导致的多申请了10字节内存。


http://www.kler.cn/a/292218.html

相关文章:

  • 深入理解 source 和 sh、bash 的区别
  • Java21和Java8性能优化详细对比
  • Win11 终端执行 python xxx.py 没反应
  • C++的一些模版
  • Kafka-Eagle的配置——kafka可视化界面
  • 力扣 LeetCode 541. 反转字符串II(Day4:字符串)
  • bug“医典”
  • Prometheus与Grafana入门:从安装到基础监控的完整指南
  • 数字政务行业ITSM案例分析报告
  • Spring Task
  • 基于BiLSTM-CRF的医学命名实体识别研究(下)模型构建
  • ITK-重采样
  • conda迁移windows虚拟环境到linux
  • React应用中的状态管理:Redux vs Context API
  • JVM系列(九) -垃圾对象的回收算法介绍
  • 深度学习回归任务训练代码模版
  • MacOS---IDEA快捷键:生成get/set方法
  • 【C++】手动实现String类的封装(分文件编译)
  • 具身智能猜想 ——机器人进化
  • 一款管理苹果设备的软件iMazing3中文破解安装激活教程
  • Node.js 数据库操作详解:构建高效的数据持久化层
  • 行空板上YOLO和Mediapipe视频物体检测的测试
  • Docker续7:docker部署nmt续1:使用haproxy代理nginx
  • 在Windows系统上部署PPTist并实现远程访问
  • 链表leetcode-1
  • 什么是新顶级域名?与传统域名有什么不同?