FreeRTOS学习笔记之内存管理
一、简介
在使用 FreeRTOS 创建任务、队列、信号量等对象的时候, FreeRTOS 一般都提供了两种方法,一种是动态地申请创建对象时所需要的内存,这种方法也叫动态方法;一种是由用户自定义对象,在编译器编译程序的时候,会为已经在程序中定义好的对象分配一定的内存空间,这种方法也叫静态方法
动态方式:自动地从 FreeRTOS 管理的内存堆中申请所创建对象所需的内存,在对象被删除后,又可以将这块内存释放会 FreeRTOS 管理的内存堆
静态方式:需要用户提供各种内存空间,例如任务的栈空间、任务控制块所用内存空间等等, 并且使用静态方式占用的内存空间一般固定下来了,即使任务、队列等被删除后,这些被占用的内存空间也没有其他用途。
FreeRTOS 提供的动态内存管理方法,标准的 C 库也提供了函数 malloc()和函数 free()来实现动态地申请和释放内存,但是标准 C 库的动态内存管理方法有如下几个缺点:
1. 占用大量的代码空间,并不适用于资源紧缺的嵌入式系统中。
2. 没有线程安全的相关机制。
3. 具有不确定性,体现在每次执行的时间不同。
4. 内存碎片化。
FreeRTOS 一共提供了 5 种动态内存管理算法,分别为: heap_1.c、 heap_2.c、 heap_3.c、 heap_4.c、 heap_5.c
什么是内存碎片化?
内存碎片化指的是内存被分割成许多小块,相邻的空闲内存无法合并,虽然总的空闲内存足够,但没有一个连续的空闲块能满足当前分配请求的情况。
碎片化分为两种:
外部碎片:当空闲内存分散在许多不连续的小块中,导致无法分配较大的连续内存块
内部碎片:分配的内存块比实际请求的大,导致块内部分内存未被使用
二、FreeRTOS 内存管理算法
算法 | 优点 | 缺点 |
heap_1.c | 分配简单,时间确定 | 只允许申请内存,不允许释放 |
heap_2.c | 允许申请和释放内存 | 不能合并相邻的空闲内存块会产生碎片、世时间不定 |
heap_3.c | 简单封装 C 库的函数 malloc()和函数 free(), 简单,以确保线程安全 | 速度慢,时间不定 |
heap_4.c | 允许申请和释放内存,并且能够合并相邻的空闲内存块,减少内存碎片的产生 | 时间不定 |
heap_5.c | 具有heap_4的能力且能够管理多个非连续内存区域的 | 时间不定 |
2.1 heap_1.c内存管理算法
heap_1 内存管理算法是 5 种内存管理算法中实现最简单的内存管理算法,但是由 heap_1 内存管理算法申请的内存,是无法被释放的。适用于无需释放任务、队列、信号量等创建时申请的内存的场景
heap_1 内存管理算法管理的内存堆实际上是一个大小为configTOTAL_HEAP_SIZE 字节的数组,宏 configTOTAL_HEAP_SIZE 可以在 FreeRTOSConfig.h文件中进行配置。由于不释放内存,所以不会产生内存碎片。
2.2 heap_2.c内存管理算法
heap_2 内存管理算法使用了最适应算法,以支持释放先前申请的内存,但是 heap_2 内存管理算法并不能将相邻的空闲内存块合并成一个大的空闲内存块,因此 heap_2 内存管理算法不可避免地会产生内存碎片;heap_2 内存管理算法的内存堆与 heap_1 内存管理算法的内存堆一样,都是一个数组,适用于频繁创建和删除任务且所创建的任务堆栈都相同的场景
heap_2 内存管理算法会通过内存块中的 pxNextFreeBlock 指针,将还未分配的内存块链成一个单向链表,这个单向链表就叫做空闲块链表。空闲块链表中的内存块是按照内存块的大小从小到大排序的,因此空闲块链表中相邻的两个内存块,其在内存中也不一定相邻。
特点:
1.可以使用在可能会删除已经创建好的任务、队列、信号量等的应用程序中,但是要注意内存碎片的产生
2.不应该被使用在多次申请和释放不固定大小内存的情况,因为这可能会导致内存碎片的情况变得严重
3.具有不确定性,但是执行的效率比标准 C 库的内存管理高得多
最适应算法:假如heap有3块空闲内存(内存由大小按从小到大排序)5字节、25字节、50字节;现在创建任务需要申请20字节的内存,系统就会找出最小且满足需求的内存大小,将申请的到的20字节地址返回,剩余的5字节仍然空闲。
2.4 heap_4.c内存管理算法
heap_4 内存管理算法使用了首次适应算法,与 heap_2 内存管理算法一样, heap_4 内存管理算法也支持内存的申请与释放,并且 heap_4 内存管理算法还能够将空闲且相邻的内存进行合并,从而减少内存碎片的现象。
heap_4 内存管理算法的内存堆与 heap_1、 heap_2 内存管理算法的内存堆一样,都是一个数组,可以在 FreeRTOSConfig.h 文件中配置 configTOTAL_HEAP_SIZE 配置项,以配置内存堆的字节大小
heap_4内存管理算法中空闲块链表中的内存块并不是按照内存块大小的顺序从小到大排序,而是按照空闲块链表中内存块的起始地址大小从小到大排序,这也是为了后续往空闲块链表中插入内存块时,能够将相邻的内存块合并
特点:
1. 适用于在程序中多次创建和删除任务、队列、信号量等的应用。2. 与 heap_2 内存管理算法相比,即使多次分配和释放随机大小的内存,产生内存碎片的几率也要小得多。
3. 具有不确定性,但是执行的效率比标准 C 库的内存管理高得多
首次适应算法:假如heap有3块空闲内存(按照内存地址由大小按从小到大排序)5字节、50字节、25字节;现在创建任务需要申请20字节的内存,系统就会从低地址到高地址找出满足需求的内存大小,将申请的到的20字节地址返回,剩余的30字节仍然空闲。
