FreeRTOS--内存管理

    FreeRTOS操作系统将内核和内存管理分开实现,操作系统内核仅规定了必要的内存管理函数原型 不关心内存管理函数是如何实现的。所以在 FreeRTOS 中提供了多种内存分配算法(分配策略),但是上层接口(API)却是统一的。这样做可以增加系统的灵活性:用户可以选择对自己更有利的内存管理策略,在不同的应用场合使用不同的内存分配策略。

在嵌入式程序设计中内存分配应该是根据所设计系统的特点来决定选择使用动态内存分配还是静态内存分配算法,一些可靠性要求非常高的系统应选择使用静态的,而普通的业务系统可以使用动态来提高内存使用效率。静态可以保证设备的可靠性但是需要考虑内存上限,内存使用效率低,而动态则是相反。
  在电脑中我们可以用 malloc()和 free()这两个函数动态的分配内存和释放内存。但是,在嵌入式实时操作系统中,调用 malloc()和 free()却是危险的,原因有以下几点:
  1. 这些函数在小型嵌入式系统中并不总是可用的,小型嵌入式设备中的 RAM 不足。
  2.  它们的实现可能非常的大,占据了相当大的一块代码空间。
  3.  他们几乎都不是安全的。
  4.  它们并不是确定的,每次调用这些函数执行的时间可能都不一样。
  5.  它们有可能产生碎片。
  6.  这两个函数会使得链接器配置得复杂。
  7.  如果允许堆空间的生长方向覆盖其他变量占据的内存,它们会成为 debug 的灾难。
   不同的嵌入式系统具有不同的内存配置和时间要求。所以单一的内存分配算法只可能适合部分应用程序。因此,FreeRTOS 将内存分配作为可移植层面(相对于基本的内核代码部言),FreeRTOS 有针对性的提供了不同的内存分配管理算法,这使得应用于不同场景的设备可以选择适合自身内存算法。FreeRTOS 的 V9.0.0 版本为我们提供了 5 种内存管理算法,分别是 heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c,源文件存放于FreeRTOS\Source\portable\MemMang 路径下,在使用的时候选择其中一个添加到我们的工程中去即可。

内存管理的应用场景:

   内存管理的主要工作是动态划分并管理用户分配好的内存区间,主要是在用户需要使用大小不等的内存块的场景中使用,当用户需要分配内存时,可以通过操作系统的内存申请函数索取指定大小内存块,一旦使用完毕,通过动态内存释放函数归还所占用内存,使之可以重复使用(heap_1.c 的内存管理除外)。例如动态分配。

内存管理方案:

heap_1.c:

FreeRTOS提供内存管理方案中最简单的一个:只能申请内存而不能进行内存释放 并且申请内存的时间是一个常量 内存利用率不高

1 、 用于从不删除任务、队列、信号量、互斥量等的应用程序(实际上大多数使用FreeRTOS 的应用程序都符合这个条件)。
2 、 函数的执行时间是确定的并且不会产生内存碎片

  1. 变量 xNextFreeByte 用来定位下一个空闲的内存堆位置。
  1. 静态变量 pucAlignedHeap 是一个指向对齐后的内存堆起始地址,我们使用一个数组作为堆内存,但是数组的起始地址并不一定是对齐的内存地址,所以我们需要得到FreeRTOS 管理的内存空间对齐后的起始地址,并且保存在静态变量 pucAlignedHeap 中。

      heap_2.c:

      采用最佳匹配算法,Heap_2.c 方案支持释放申请的内存,但是它不能把相邻的两个小的内存块合成一个大的内存块,对于每次申请内存大小都比较固定的,这个方式是没有问题的,而对于每次申请并不是固定内存大小的则会造成内存碎片

heap_2.c 方案具有以下特点:
   1. 可以用在那些反复的删除任务、队列、信号量、等内核对象且不担心内存碎片的
应用程序。
   2. 如果我们的应用程序中的队列、任务、信号量、等工作在一个不可预料的顺序,
这样子也有可能会导致内存碎片。
   3. 具有不确定性,但是效率比标准 C 库中的 malloc 函数高得多
   4. 不能用于那些内存分配和释放是随机大小的应用程序。

 内存申请函数 pvPortMalloc():

内存释放函数 vPortFree():
    分配内存的过程简单,那么释放内存的过程更简单,只需要向内存释放函数中传入要
释放的内存地址,那么系统会自动向前索引到对应链表节点,并且取出这块内存块的信息,
将这个节点插入到空闲内存块链表中,将这个内存块归还给系统.

 

heap_3.c:

    heap_3.c 方案只是简单的封装了标准 C 库中的 malloc()free()函数,并且能满足常用的编译器。重新封装后的 malloc()free()函数具有保护功能,采用的封装方式是操作内存前挂起调度器、完成后再恢复调度器。

heap_3.c 方案具有以下特点:

1 、 需要链接器设置一个堆, malloc() free() 函数由编译器提供。
2 、 具有不确定性。
3 、 很可能增大 RTOS 内核的代码大小。
heap_4.c:
    heap_4.c 方案与 heap_2.c 方案一样都采用最佳匹配算法来实现动态的内存分配,但是不一样的是 heap_4.c 方案还包含了一种合并算法,能把相邻的空闲的内存块合并成一个更 大的块,这样可以减少内存碎片。 heap_4.c 方案特别适用于移植层中可以直接使用 pvPortMalloc() vPortFree() 函数来分配和释放内存的代码。
  
heap_4.c 方案具有以下特点:
1 、可用于重复删除任务、队列、信号量、互斥量等的应用程序
2 、可用于分配和释放随机字节内存的应用程序,但并不像 heap2.c 那样产生严重的内
存碎片。
3 、具有不确定性,但是效率比标准 C 库中的 malloc 函数高得多
内存申请函数 pvPortMalloc()  内存释放函数 vPortFree() :

 heap_5.c:

   采用最佳匹配算法和合并算法,并且允许内存堆跨越多个非连续的内存区,也就是允许在不连续的内存堆中实现内存 分配,比如用户在片内 RAM 中定义一个内存堆,还可以在外部 SDRAM 再定义一个或多 个内存堆,这些内存都归系统管理。
heap_5.c 方案通过调用 vPortDefineHeapRegions() 函数来实现系统管理的内存初始化,在内存初始化未完成前不允许使用内存分配和释放函数。
使用实例:

 

实验:

    创建了两个任务,分别是 LED 任务与内存管理测试任务,内存管理测试任务通过检测按键是否按下来申请内存或释放内存, 当申请内存成功就像该内存写入一些数据,如当前系统的时间等信息,并且通过串口输出 相关信息; LED 任务是将 LED 翻转,表示系统处于运行状态。在不需要再使用内存时,注 意要及时释放该段内存,避免内存泄露。
 

 

  

实验现象:

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值