一、heap.c 是什么?

  1. 它是 FreeRTOS 官方提供的堆管理源码FreeRTOS 自带 5 个独立的堆管理文件:heap_1.c ~ heap_5.c。在 CubeMX 里选择 Heap_4 后,软件会自动把 heap_4.c 重命名为 heap.c 加入你的工程。

  2. 它不是编译器自带的,是 RTOS 专用的和 C 语言标准库的 malloc/free 无关,是 FreeRTOS 为嵌入式单片机量身定制的内存管理。


二、heap.c 的作用?

它的唯一使命:为 FreeRTOS 提供安全、高效的动态内存服务。你在代码里调用这些函数时,底层全靠 heap.c 来分配 / 回收内存

  • xTaskCreate():创建任务 → 申请任务栈 + 任务控制块内存
  • xQueueCreate():创建队列 → 申请队列内存
  • osSemaphoreNew():创建信号量 → 申请信号量内存
  • 自定义动态内存申请:pvPortMalloc() / vPortFree()

简单说:没有 heap.c,FreeRTOS 就无法创建任何动态对象!

核心一句话:它们的本质是 pvPortMalloc()(动态分配)和 vPortFree()(释放)的不同实现,区别只在于:能不能释放、能不能合并碎片、效率高低


前置基础

  1. FreeRTOS 动态内存(创建任务 / 队列 / 信号量)全靠这 5 种堆管理;
  2. 内存来源:Heap_1/2/4/5configTOTAL_HEAP_SIZE 定义的静态数组;Heap_3 用编译器标准库堆;
  3. 中断中禁止调用内存分配 / 释放函数

三、逐类详解

1. Heap_1 → 只分配,不释放

原理

用一个静态数组当堆,分配内存时指针往后挪,完全不实现释放功能。

优点

  • 代码最简单、执行最快
  • 零内存碎片(永远不会碎片化)
  • 线程安全、永不崩溃

缺点

  • vPortFree() 完全无效,不能释放任何内存

使用场景

小型 / 极简项目:任务、队列、信号量创建后永不删除(90% 的简单 STM32 项目都能用)。


2. Heap_2 → 可分配 + 释放,但不合并碎片(淘汰边缘)

原理

基于空闲链表分配,支持释放,但不会合并相邻的空闲内存块

优点

  • 支持内存释放
  • 不依赖 C 标准库,效率比 Heap_3 高

缺点

  • 致命问题:内存碎片严重反复分配 / 释放不同大小的内存,会产生很多小碎块,最终导致分配失败。

使用场景

仅用于固定大小的内存分配:比如只分配固定大小的消息缓存,绝对不混用不同大小的内存,几乎不推荐新手使用


3. Heap_3 → 封装 C 标准库 malloc/free(兼容版)

原理

直接包装编译器自带的 malloc()free(),仅增加了线程安全保护

优点

  • 兼容标准 C 语言库
  • 不用配置 FreeRTOS 堆大小

缺点

  • 依赖编译器库,效率低
  • 堆大小由链接脚本控制,不可控
  • 线程安全靠关中断,影响实时性

使用场景

特殊需求:需要和 C 标准库内存混用,或特殊编译器环境;单片机项目强烈不推荐


4. Heap_4 → 可分配 + 释放 + 合并碎片(🔥 官方首选、实战最常用)

原理

在 Heap_2 基础上,增加了相邻空闲块自动合并功能,完美解决内存碎片。

优点

  • 支持任意大小内存的分配 / 释放
  • 自动合并碎片,内存利用率极高
  • 线程安全、效率高
  • 代码复杂度适中

缺点

  • 比 Heap_1 代码稍多

使用场景

中大型 / 复杂项目:动态创建 / 删除任务、队列、信号量;随机大小的内存分配;STM32CubeMX 默认选择 Heap_4


5. Heap_5 → Heap_4 增强版,支持多块不连续 RAM

原理

和 Heap_4 完全一样,唯一区别:支持管理多个不连续的 RAM 区域

优点

  • 拥有 Heap_4 所有优点
  • 可跨区域使用内存(片内 RAM + 外部 RAM / 多个分散 RAM)

缺点

  • 需要手动初始化堆地址

使用场景

高端 STM32 芯片:RAM 不连续(如 STM32H7/F7,带多个 RAM 块、外部 SRAM/SDRAM)。


四、核心对比表

表格

方案支持释放合并碎片内存碎片效率依赖推荐指数
Heap_1-❌(无)⭐⭐⭐⭐⭐⭐⭐⭐
Heap_2⭐⭐⭐⭐⭐(严重)⭐⭐⭐⭐
Heap_3⭐⭐⭐⭐C 标准库
Heap_4❌(极少)⭐⭐⭐⭐⭐⭐⭐⭐⭐
Heap_5❌(极少)⭐⭐⭐⭐⭐⭐⭐⭐

五、选型建议

  1. 简单项目(LED、按键、简单传感器)Heap_1,稳定无碎片,不用操心释放。
  2. 绝大多数项目(动态任务、队列、消息)Heap_4,STM32 默认配置,万能方案。
  3. 大内存 / 多 RAM 区域芯片(H7/F7)Heap_5
  4. 绝对不要选 Heap_2 / Heap_3,除非有特殊需求。

六、关键补充

  1. 堆大小配置FreeRTOSConfig.hconfigTOTAL_HEAP_SIZE 就是堆总大小(单位:字节)。
  2. 内存查看xPortGetFreeHeapSize() 可以查看剩余堆内存,方便调试。
  3. 通用规则所有动态内存分配,都不允许在中断服务函数中使用
Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐