极客秀
搜索

FreeRTOS中的heap你是否选择对了?介绍heap1~5的区别以及如何选择!

** 1 **

** 前言 **

在之前有一期文章介绍自己在使用FreeRTOS的时候遇到过的一个中断优先级的问题。

其中我们在文末提到过一句遇到的问题可能是由于heap选择错误的问题。

本期我们来探究一下FreeRTOS提供heap1~heap5分别有什么区别,我们需要如何选择。

** 2 **

** 堆栈 **

堆栈在计算机原理数据结构中有着非常多的篇幅,不过 ** 内存管理的堆栈 ** 和 数据结构的堆栈
有所区别。内存空间的堆栈是两种内存分配区域,它们在内存分配方式、使用场景以及生命周期上有着显著的区别。

数据结构的堆栈是两种特殊的数据结构。我们着重介绍 ** 内存管理的堆栈概念 ** 。

** 计算机中 ** 的栈是一种先进后出的结构,在程序运行时,栈用于 ** 存储局部变量、函数参数、函数调用的返回地址 **
等信息(临时)。栈内存由操作系统自动管理,程序员不需要手动分配和释放内存。内存是连续的,内存的分配和回收速度非常快。

堆是程序用来 ** 动态分配 ** 内存的区域。堆的内存分配通常由程序员显式管理,程序员需要 ** 手动申请和释放 **
堆内存。堆内存的分配速度相对较慢,但堆内存的大小比栈内存要大得多,且堆内存的生命周期由程序员控制。这方面就涉及了C语言的动态内存分配,在C语言中有Malloc函数申请空间,free函数释放空间。C++中new函数申请空间,Delete函数释放空间。

** 3 **

** 嵌入式的堆栈 **

在单片机中的堆栈相比于电脑上的堆栈有着些许区别,单片机的堆栈空间在RAM(随机存储器)中,首先面临的问题就是空间大小。

如STM32F103C8T6的RAM是20KB。这代表着堆栈总空间不能超过20kB。

在启动文件中,我们可以看到定义的堆栈空间默认大小。这些参数分别代表着: ** 栈区大小:1kB,栈区名字
STACK,栈区不进行初始化(从默认地址启动),栈区字节对齐2^3 = 8字节。ReadWrite可读可写 ** 。

堆区如是,不过分配的空间是512kB。

从使用的角度来看栈大小代表着: ** 局部变量、函数调用信息、返回地址、中断上下文的大小不能超过1Kb ** 。

堆大小即动态分配内存,即我们可以使用malloc的空间不能超过512kB。

像这样子,102428供2kB,超过了临时变量1KB的大小,就造成了栈溢出,程序并没有运行这段内容。

系统会进入异常中断(开编译器优化的话这个问题可能会被编译器优化掉)所以大家尽可能不要创建太大的临时变量防止栈溢出。

在单片机中没有内存管理单元(MMU)但是在一些实时操作系统,例如FreeRTOS中就需要大量的涉及到动态内存分配,因此FreeRTOS
提供了几种内存分配策略,这些策略通常被实现为不同的 ** 堆管理算法(heap) ** 。

** 4 **

** 堆管理算法 **

FreeRTOS本身的堆管理较为简单、高效。 ** 大家在使用FreeRTOS的时候是否疑惑,heap1.c,heap2.c……这些的区别是什么? **
该如何选择?再STM32F103中默认选择了heap4, 但是在STM32H5中需要自己选择heap
因此出现了上次的错误,为此才去深入的了解一下heap的区别。

例如CubeMX中STM32F103C8T6的默认推荐是heap_4。

它们的区别我们可以去FreeRTOS的官网查看其介绍。

heap1是最简单的内存管理,不允许释放内存。heap2实现了malloc和free(注意 ** 单片机中的malloc和free需要我们自己实现 **
)允许释放内存,但是不合并空闲块。

heap3利用标准C库的malloc和free。heap4在heap2的基础上进行合并空闲块,更加灵活。

heap5在heap4的基础上可以跨越多个内存块,即有了 ** 内存池 **
的概念。内存池是一种用于为特定类型的内存请求提供预分配内存块的技术。这样可以减少动态内存分配的碎片化,提高内存分配的效率。

可以看到不同的heap其实区分的是:不同的malloc和free ** 函数的实现 ** 以及 ** 空闲块的处理 ** 。

这里稍微解释一下空闲块和碎片。空闲块就是内存空间(堆)中未被分配的空间,处于一个空闲状态等待系统分配。

碎片是存在很多小的空闲块,这些空闲块虽然总和足够大,但由于它们分散在内存池中,可能无法满足较大的内存请求。合并碎片就是将这些零零碎碎的碎片合并起来成为一个足够大的空间。

说到这里,其实大家就能明白,FreeRTOS的heap选择几乎是固定的。heap1和heap2太旧了,完全可以被heap4替代。

** heap3不提供嵌入式的malloc和free ** ,需要硬件资源有MMU。因此选择heap3会导致不能工作。

因此选择几乎被固定在heap4和heap5。

** 5 **

** 4 or 5 ? **

在选择4或者5的时候,我们先看看heap5的使用要求。

heap5需要使用者先进行不同的内存区块划分,之后并且对Heap进行 ** 初始化 ** !很重要,要初始化的!并不是heap4那样子直接用的。

这里我使用STM32H563,在FreeRTOS初始化的时候进行内存空间初始化,官网的文档中介绍的是在Win32的情况下,这里我修改成单片机的地址。

不过在STM32F103C8中,本身SRAM空间就不是很大,为了防止溢出,其实本身能分成的内存块就比较少。


const HeapRegion_t xHeapRegions[] =  {      { ( uint8_t * ) 0x20000000UL, 0x01000 },  // 堆区域 1,从 0x20000000 开始,大小32KB    { ( uint8_t * ) 0x20001000UL, 0x01000 },  // 堆区域 1,从 0x20001000 开始,大小32KB    { NULL, 0 }  // 结束标记};

所以不是不能用heap5,只是很没有必要。heap4就已经绰绰有余了。

反观如果像H7,H5这种本身RAM比较大,而且再外接SRAM的话,为了更加精细化的内存管理,可以选择使用heap5来替代heap4。不过关键千万别忘记了
** 初始化 ** !!!

1.转载请保留原文链接谢谢!
2.本站所有资源文章出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。
3.本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户擦亮眼睛自行鉴别,做一个有主见和判断力的用户。
4.本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。
5.联系方式(#替换成@):pm#vimge.com

  相关内容