11-内存管理.md 3.7 KB


tags: [source-summary] type: source source: "尚硅谷嵌入式技术之FreeRTOS实时操作系统 V1.0.3 — 第19章 + 配套代码21" author: "尚硅谷研究院" date: 2026-07-12 url: ""

created: 2026-07-12

内存管理

用生活理解:内存管理就像图书馆的座位管理——

  • heap_1:图书馆只进不出,每个人来了就固定坐一个位置,永远不走(最简单)
  • heap_2:可以走了,但走之后留下的空位不合并——时间长了满是小缝隙,大桌子放不下
  • heap_4:有人走了,把旁边空位合并成大空间(推荐!)
  • heap_5:图书馆有多个独立区域,可以跨区域管理座位

为什么 FreeRTOS 不用标准 malloc?

在嵌入式系统中,标准 C 库的 malloc()/free() 有这些问题:

  1. 不一定可用——很多 MCU 开发环境没带完整 C 库
  2. 占用代码空间——printf、malloc 全家桶很大
  3. 非线程安全——两个任务同时 malloc 可能崩溃
  4. 非确定性——malloc 执行时间不确定(RTOS 要求确定!)

五种 heap 算法对比

算法 合并空闲块 允许释放 适用场景 推荐?
heap_1 不适用 ❌ 不能释放 只创建不删除的项目
heap_2 任务栈大小固定 ❌ 已过时
heap_3 由C库决定 标准库可用时
heap_4 通用场景 ⭐ 推荐
heap_5 ✅(跨区域) 内存地址不连续

heap_1:最简单(不能释放)

初始化: [         整个堆空间          ]
分配后: [ Task1 ][ Task2 ][ Task3 ][ 剩余 ]

一次分配、永不释放。适用于项目启动时创建所有任务/队列,运行中不删除任何东西。

heap_2:最佳适应(过时)

释放后: [ Task1 ][ 空闲 ][ Task3 ][ 空闲 ]
         ↑不合并          ↑不合并
        变成小碎片        变成小碎片
分配16字节:选"最适合"的块(不一定是最大的)
问题:碎片越来越多,最终大块分配失败

heap_4:第一适应 + 合并(推荐)

释放后: [ Task1 ][ 空闲 ][ Task3 ][ 空闲 ]
         ↓自动合并相邻空闲块
         [ Task1 ][   大空闲空间   ]
分配时:选"第一个足够大的"块

最多碎片控制:相邻空闲块自动合并,减少碎片。

heap_5:跨区域 heap_4

内存布局: [ 区域A 128KB ]    [ 区域B 64KB ]    [ 区域C 32KB ]
           ↑ 不连续但heap_5能统一管理

示例:内存管理(项目21)

核心代码

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);
    }
}

内存 API

函数 作用 类比
pvPortMalloc(size) 申请 size 字节 跟图书馆说"我要坐这儿"
vPortFree(ptr) 释放之前申请的内存 离开座位
xPortGetFreeHeapSize() 查还剩多少堆空间 看看图书馆还有多少空位

配套代码

  • code/21_内存管理/

相关:[[03-FreeRTOS移植指南]](移植时需选择 heap_4.c)