tags: [source-summary] type: source source: "尚硅谷嵌入式技术之FreeRTOS实时操作系统 V1.0.3 — 第19章 + 配套代码21" author: "尚硅谷研究院" date: 2026-07-12 url: ""
用生活理解:内存管理就像图书馆的座位管理——
- heap_1:图书馆只进不出,每个人来了就固定坐一个位置,永远不走(最简单)
- heap_2:可以走了,但走之后留下的空位不合并——时间长了满是小缝隙,大桌子放不下
- heap_4:有人走了,把旁边空位合并成大空间(推荐!)
- heap_5:图书馆有多个独立区域,可以跨区域管理座位
在嵌入式系统中,标准 C 库的 malloc()/free() 有这些问题:
| 算法 | 合并空闲块 | 允许释放 | 适用场景 | 推荐? |
|---|---|---|---|---|
| heap_1 | 不适用 | ❌ 不能释放 | 只创建不删除的项目 | |
| heap_2 | ❌ | ✅ | 任务栈大小固定 | ❌ 已过时 |
| heap_3 | 由C库决定 | ✅ | 标准库可用时 | |
| heap_4 | ✅ | ✅ | 通用场景 | ⭐ 推荐 |
| heap_5 | ✅(跨区域) | ✅ | 内存地址不连续 |
初始化: [ 整个堆空间 ]
分配后: [ Task1 ][ Task2 ][ Task3 ][ 剩余 ]
一次分配、永不释放。适用于项目启动时创建所有任务/队列,运行中不删除任何东西。
释放后: [ Task1 ][ 空闲 ][ Task3 ][ 空闲 ]
↑不合并 ↑不合并
变成小碎片 变成小碎片
分配16字节:选"最适合"的块(不一定是最大的)
问题:碎片越来越多,最终大块分配失败
释放后: [ Task1 ][ 空闲 ][ Task3 ][ 空闲 ]
↓自动合并相邻空闲块
[ Task1 ][ 大空闲空间 ]
分配时:选"第一个足够大的"块
最多碎片控制:相邻空闲块自动合并,减少碎片。
内存布局: [ 区域A 128KB ] [ 区域B 64KB ] [ 区域C 32KB ]
↑ 不连续但heap_5能统一管理
void task1(void *pvParameters)
{
uint8_t key = 0;
void *buff = NULL;
while (1)
{
key = Key_Detect();
if (key == KEY1_PRESS)
{
// 申请20字节内存
buff = pvPortMalloc(20);
if (buff != NULL) {
printf("申请20字节成功!剩余堆=%d\r\n",
xPortGetFreeHeapSize());
}
}
else if (key == KEY2_PRESS)
{
// 释放内存
vPortFree(buff);
printf("释放成功!剩余堆=%d\r\n",
xPortGetFreeHeapSize());
}
vTaskDelay(500);
}
}
| 函数 | 作用 | 类比 |
|---|---|---|
pvPortMalloc(size) |
申请 size 字节 | 跟图书馆说"我要坐这儿" |
vPortFree(ptr) |
释放之前申请的内存 | 离开座位 |
xPortGetFreeHeapSize() |
查还剩多少堆空间 | 看看图书馆还有多少空位 |
code/21_内存管理/相关:[[03-FreeRTOS移植指南]](移植时需选择 heap_4.c)