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

【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.mrgr.cn/news/20567.html

相关文章:

  • 内存管理篇-22 高端内存和低端内存的分界线
  • Newman生成测试报告排版混乱
  • Spring 源码解读:手动实现BeanFactory的加载与管理
  • C++的四种规范的类型转换
  • 动手学深度学习(pytorch)学习记录24-填充和步幅[学习记录]
  • java开发简历详解
  • 2024国赛数学建模C题思路模型
  • 设计模式之装饰器模式:让对象功能扩展更优雅的艺术
  • 为什么这么多物联网项目都失败了?
  • Python
  • OpenCV 旋转矩形边界
  • HTTP Cookie 和 session
  • 2024 年全国大学生数学建模竞赛(国赛)浅析
  • 利用高德API获取整个城市的公交路线并可视化(四)
  • 数据链路层认识以太网
  • 使用C语言实现字符推箱子游戏
  • C++学习笔记(7)
  • 用Java实现一个简易的炸金花小游戏
  • 一站式开发平台ModelArtls
  • WS2812B驱动