freeRTOS内存管理
freeRTOS内存管理
概述
,大小由 configTOTAL_HEAP_SIZE 决定,系统启动时就已经放在 RAM 里,
不需要手动申请,它只是被 pvPortMalloc() 动态“使用”而已。
🧩 一、堆(Heap)不是运行时申请的,而是编译时静态分配的!
也就是说:
堆这块内存,在你烧录程序进 MCU 前,就已经被编译器在 RAM 里划出来了。
它不是用 malloc() 或某个函数“申请”的,而是你选用的 heap_x.c 文件里定义的一块静态数组。
🧠 二、看看源码就明白了
比如你工程里使用的是 heap_4.c(最常用的版本)。
打开 FreeRTOS/portable/MemMang/heap_4.c,里面有这一段:
/* 定义一块静态数组作为堆空间 */
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
/* 堆的总大小来自 FreeRTOSConfig.h */
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 10 * 1024 ) )这就表示:
在 RAM 里留出 10KB 空间,作为 FreeRTOS 的“堆内存池”。
🧰 三、谁来管理这块堆?
FreeRTOS 内部有个专门的分配器函数:
void *pvPortMalloc(size_t xWantedSize);
void vPortFree(void *pv);这两个函数操作的就是上面那个 ucHeap[] 数组。
也就是说:
pvPortMalloc():从ucHeap[]数组中找出一段空闲区域;vPortFree():释放这段区域,让以后能再次用。
🧮 四、系统初始化时什么时候生效?
当你调用 xTaskCreate()、xQueueCreate()、xSemaphoreCreateBinary() 等 FreeRTOS API 时,
这些函数会在内部调用 pvPortMalloc() 去堆里要内存。
比如:
xTaskCreate(Task_LED, "LED", 128, NULL, 1, NULL);👉 实际上内部调用了:
pxNewTCB = (TCB_t *)pvPortMalloc(sizeof(TCB_t)); // 分配任务控制块
pxStack = (StackType_t *)pvPortMalloc(stack_size); // 分配任务栈所以堆就在这里被真正“用起来”了。
创建队列,任务,信号量有两种方法,要么动态,要么静态,对于静态,自己管理好就行。对于动态,就要内存管理
使用标准C库的malloc()和free()也可以实现动态内存管理,但是

不同的系统对内存的分配和时间要求不同,因此freertos提供了自己的内存分配算法

内存碎片

一开始创建4个任务,那么接下来如果有在地址不连续的任务提前释放,就会形成碎片
内存分配方法
heap_1
创建之后不可以回收

heap_2
会有碎片产生

heap_3

heap_4


裸机系统:
text
内存布局:
+------------------+
| 栈 | ← main函数的栈
+------------------+
| 堆 | ← 标准C库管理的堆(malloc/free)
+------------------+
| 数据段 | ← 全局变量
+------------------+
| 代码区 |
+------------------+RTOS系统:
text
内存布局:
+------------------+
| 任务1栈 | ← 从RTOS堆分配
+------------------+
| 任务2栈 | ← 从RTOS堆分配
+------------------+
| RTOS堆 | ← FreeRTOS自己管理的"堆"(其实是个大数组)
+------------------+
| 标准库堆 | ← 可能很小甚至没有
+------------------+
| 数据段 |
+------------------+
| 代码区 |
+------------------+裸机堆区就是一块未使用的内存,这块内存专门留给自己手动申请,释放
OS的任务栈也是从堆区里面划分的,堆区是一个数组的占用空间

