FreeRTOS基础篇(五)——内存管理
FreeRTOS基础篇(五)——内存管理
前言:
本篇文章介绍FreeRTOS的移植方法,以stm32f103举例。
1 介绍
FreeRTOS作为一个轻量级的实时操作系统(RTOS),在资源受限的嵌入式系统中广泛应用。由于其不依赖标准c库的动态内存管理(如 malloc / free),FreeRTOS提供了多种灵活且可配置的内存管理方案,以满足不同应用场景对性能、安全性和内存碎片的要求。
FreeRTOS不直接使用c标准库中的 malloc() 和 free(),而是提供了一套可移植、可配置的内存管理机制,以适应资源受限的嵌入式环境。其核心思想是:将一块静态定义的内存区域作为堆(heap),由 FreeRTOS 的内存管理模块进行分配和释放。
内存管理主要是为了解决内存碎片化的问题。
- 碎片成因:频繁分配/释放不同大小的内存块,导致虽然总空闲内存足够,但无法分配大块连续内存。
- 缓解措施:
- 使用
heap_4或heap_5(支持合并空闲块)。 - 尽量使用固定大小的内存池(如静态队列、任务栈预分配)。
- 避免频繁创建/删除内核对象。
- 使用
2 五种内存管理方案(Heap_1 至 Heap_5)
FreeRTOS提供了5种不同的内存管理实现,位于 Source/portable/MemMang/ 目录下:
2.1 heap_1.c
最简单,仅支持分配,不支持释放
- 特点:
- 只能分配内存,不能释放。
- 所有分配的内存一直存在,直到系统关闭。
- 适用场景:
- 所有任务、队列、信号量在启动时创建,运行期间不再删除。
- 优点:简单、无碎片、效率高。
- 缺点:无法动态释放内存。
适合小型固件,所有资源在初始化阶段创建。
2.2 heap_2.c
支持释放,使用首次适配(First Fit)算法
- 特点:
- 支持
pvPortMalloc()和vPortFree()。 - 使用“首次适配”策略从空闲块中分配内存。
- 不会合并相邻的空闲块,容易产生内存碎片。
- 支持
- 适用场景:
- 动态创建/删除任务或队列,但频率不高。
注意:不适合频繁分配/释放不同大小内存的场景。
2.3 heap_3.c
使用标准 malloc() 和 free()
- 特点:
- 包装了c库的
malloc()和free()。 - 需要链接器提供堆空间(如
_sbrk实现)。 - 受限于底层c库的实现(可能不可重入、非线程安全)。
- 包装了c库的
- 优点:充分利用系统堆。
- 缺点:
- 需确保
malloc/free是线程安全的(通常需加锁)。 - 在某些嵌入式平台上不可靠或不可用。
- 需确保
常用于带有完整 C 运行时环境的平台(如 Linux 模拟环境)。
2.4 heap_4.c
支持释放+合并空闲块(最佳选择之一)
- 特点:
- 基于
heap_2改进,会合并相邻的空闲块,减少碎片。 - 使用“首次适配”策略。
- 分配大块内存更高效。
- 基于
- 优点:
- 支持动态分配与释放。
- 内存利用率高,适合长期运行的应用。
- 推荐使用场景:
- 大多数实际项目推荐使用
heap_4。
- 大多数实际项目推荐使用
注意:需要定义
configTOTAL_HEAP_SIZE来指定堆大小。
2.5 heap_5.c
支持多区域堆(适用于非连续内存)
- 特点:
- 允许堆分布在多个不连续的内存区域(例如:SRAM1 + SRAM2)。
- 需要调用
vPortDefineHeapRegions()显式定义内存区域。 - 使用方式类似
heap_4,支持合并空闲块。
- 适用场景:
- MCU 有多个 RAM 区域(如 STM32 的 CCM RAM、DTCM RAM 等)。
示例:
1 | const HeapRegion_t xHeapRegions[] = { |
注意:
heap_5.c要求在调用任何内存分配函数(如pvPortMalloc)之前,必须先调用vPortDefineHeapRegions()初始化堆区域。
3 配置与使用方法
3.1 选择 heap 实现
在项目中,只能包含一个 .c 文件(heap_1.c 到 heap_5.c 中选其一),通过编译时决定使用哪种策略。选择的建议整理如下。
| 场景 | 推荐方案 |
|---|---|
| 所有任务/队列静态创建,不删除 | heap_1(最安全高效) |
| 动态创建但不频繁释放 | heap_2(谨慎使用) |
| 需要完整 malloc/free 支持 | heap_3(确保线程安全) |
| 通用嵌入式应用(推荐) | heap_4(首选) |
| 多块非连续 RAM 区域 | heap_5(高级用法) |
3.2 配置项(FreeRTOSConfig.h)
configTOTAL_HEAP_SIZE:定义可用堆的总大小(仅用于 heap_1/2/4)。
1 |
- 对于
heap_5,不需要此宏,因为堆大小由vPortDefineHeapRegions()指定。
4 API
FreeRTOS提供以下内存管理 API:
| 函数 | 说明 |
|---|---|
void* pvPortMalloc(size_t xSize) |
分配指定字节的内存(等价于 malloc) |
void vPortFree(void* pv) |
释放内存(等价于 free) |
size_t xPortGetFreeHeapSize(void) |
获取当前剩余堆空间(heap_4 和 heap_5 支持) |
size_t xPortGetMinimumEverFreeHeapSize(void) |
获取历史最小空闲堆大小(用于监控碎片) |
注意:
xPortGetMinimumEverFreeHeapSize()只在heap_4.c和heap_5.c中有效,需启用configUSE_TRACE_FACILITY和configUSE_STATS_FORMATTING_FUNCTIONS(或相关配置)。
5 查看内存使用情况
FreeRTOS 提供了一些工具帮助分析内存使用情况。
1 | // 查看剩余内存 |
可用于实时监控内存使用,判断是否存在内存泄漏或碎片化问题。
minFreeHeap 越小,说明系统运行过程中内存碎片越严重,内存使用效率越低。反之, minFreeHeap 较大则表示系统在运行过程中保持了较多的可用内存,内存管理较为高效。因此,监控 minFreeHeap 的值有助于评估和优化FreeRTOS应用的内存使用情况。





