堆内存管理
2026/7/16大约 8 分钟内核组件内核内存管理堆内存
堆内存管理
📚 本节导读
学习时长: 约 30 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: 4.4 内存管理、C 语言动态内存(malloc/free)
堆内存(Heap)是 OneOS 中最灵活的内存分配方式。它允许在运行时按需分配任意大小的内存块,并在使用完毕后释放。OneOS 不仅提供了简洁的默认堆 API(与标准 C 库风格一致),还支持多堆实例的管理,方便在不同内存区域进行独立的内存管理。
🎯 学习目标
- 掌握默认堆的初始化与内存区域添加方法
- 熟练使用
os_malloc、os_free、os_realloc、os_calloc等默认堆 API - 理解多堆机制,能创建和管理自定义堆实例
- 掌握堆内存统计信息的获取方法
- 了解堆完整性检查功能
一、堆内存概念
1.1 什么是堆
堆是一块由操作系统管理的内存区域,程序可以在运行时从该区域动态申请和释放任意大小的内存块。与栈(Stack)不同,堆内存的生命周期由程序员显式控制,不受函数调用栈的限制。
┌──────────────────────────────────────────────────────────────┐
│ 系统内存布局 │
│ │
│ 高地址 │
│ ┌──────────┐ │
│ │ 栈 │ ← 函数调用、局部变量(自动分配/释放) │
│ │ ↓ │ │
│ │ │ │
│ │ ↑ │ │
│ │ 堆 │ ← 动态分配(手动分配/释放,由 OneOS 管理) │
│ ├──────────┤ │
│ │ BSS段 │ ← 未初始化全局变量 │
│ ├──────────┤ │
│ │ DATA段 │ ← 已初始化全局变量 │
│ ├──────────┤ │
│ │ TEXT段 │ ← 代码 │
│ └──────────┘ │
│ 低地址 │
└──────────────────────────────────────────────────────────────┘1.2 OneOS 堆架构
OneOS 的堆内存管理采用分层架构:
┌──────────────────────────────────────┐
│ 应用层 API │
│ os_malloc / os_free / os_realloc │
│ os_calloc / os_aligned_malloc │
└──────────────┬───────────────────────┘
│
┌──────────────▼───────────────────────┐
│ 默认堆 (Default Heap) │
│ os_default_heap_init / add │
└──────────────┬───────────────────────┘
│
┌──────────────▼───────────────────────┐
│ 多堆管理层 (Multi-Heap) │
│ os_heap_init / os_heap_alloc ... │
└──────────────┬───────────────────────┘
│
┌──────────────▼───────────────────────┐
│ 内存算法层 (Algorithm) │
│ FIRSTFIT / BUDDY │
└──────────────────────────────────────┘二、配置依赖
使用堆内存管理需要以下配置:
#define OS_USING_HEAP /* 必须 */
#define OS_USING_SEMAPHORE /* 必须(堆依赖信号量进行并发保护) */
#define OS_USING_ALG_FIRSTFIT /* 至少选择一种算法 */
/* 或 */
#define OS_USING_ALG_BUDDY /* 至少选择一种算法 */三、默认堆 API
默认堆是 OneOS 提供的一个全局堆实例,其 API 风格与标准 C 库类似,使用最为便捷。所有 API 定义在 kernel/include/os_memory.h 中。
3.1 初始化默认堆
void os_default_heap_init(void);- 功能:初始化默认堆控制块,创建名为
"DEFAULT_HEAP"的堆实例 - 调用时机:在系统启动阶段,添加内存区域之前调用
- 注意:此函数只初始化控制块,不分配实际内存区域
3.2 添加内存区域
os_err_t os_default_heap_add(void *start_addr, os_size_t size, enum os_mem_alg alg);| 参数 | 类型 | 说明 |
|---|---|---|
start_addr | void * | 内存区域的起始地址 |
size | os_size_t | 内存区域大小(字节) |
alg | enum os_mem_alg | 内存管理算法,可选 OS_MEM_ALG_FIRSTFIT、OS_MEM_ALG_BUDDY 或 OS_MEM_ALG_DEFAULT |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 添加成功 |
OS_INVAL | 参数无效或内存区域重叠 |
OS_NOMEM | 内存区域太小 |
- 功能:向默认堆添加一块可用内存区域,可以多次调用以组合多个不连续的内存区域
- 注意:
OS_MEM_ALG_DEFAULT会使用配置表中第一个注册的算法(即OS_MEM_ALG_FIRSTFIT或OS_MEM_ALG_BUDDY)
3.3 分配内存
void *os_malloc(os_size_t size);- 功能:从默认堆中分配
size字节的内存 - 参数:
size— 请求的内存大小(字节) - 返回值:成功返回内存指针,失败返回
OS_NULL - 注意:分配的内存内容是未初始化的
void *os_aligned_malloc(os_size_t align, os_size_t size);- 功能:从默认堆中分配内存,返回地址按
align字节对齐 - 参数:
align— 对齐字节数,必须是 2 的幂size— 请求的内存大小(字节)
- 返回值:成功返回对齐后的内存指针,失败返回
OS_NULL
void *os_calloc(os_size_t count, os_size_t size);- 功能:分配
count * size字节的内存,并将内存初始化为零 - 参数:
count— 元素个数size— 每个元素大小(字节)
- 返回值:成功返回内存指针,失败返回
OS_NULL
3.4 释放内存
void os_free(void *ptr);- 功能:释放之前通过
os_malloc、os_realloc、os_calloc或os_aligned_malloc分配的内存 - 参数:
ptr— 要释放的内存指针 - 注意:释放后指针不再有效,不应继续使用
3.5 重分配内存
void *os_realloc(void *ptr, os_size_t size);- 功能:调整已分配内存块的大小
- 参数:
ptr— 原内存指针(若为OS_NULL,行为等同于os_malloc)size— 新的大小(字节),若为 0,行为等同于os_free)
- 返回值:成功返回新内存指针,失败返回
OS_NULL(原内存保持不变) - 注意:重分配可能移动内存位置,返回的指针可能与原指针不同
3.6 获取堆信息
void os_default_heap_info(os_meminfo_t *info);- 功能:获取默认堆的统计信息
- 参数:
info— 指向os_meminfo_t结构体的指针,用于接收统计信息
3.7 堆完整性检查
os_err_t os_default_heap_check(void);- 功能:检查默认堆的完整性,验证所有内存块的数据结构是否一致
- 返回值:
OS_SUCCESS表示堆正常,其他值表示发现错误
四、默认堆使用示例
#include <os_memory.h>
/* 在系统启动时初始化堆 */
void board_memory_init(void)
{
/* 初始化默认堆控制块 */
os_default_heap_init();
/* 添加 64KB 堆内存区域,使用默认算法 */
os_default_heap_add((void *)0x20000000, 64 * 1024, OS_MEM_ALG_DEFAULT);
}
/* 应用代码中使用堆内存 */
void app_task(void)
{
os_meminfo_t info;
char *buf1;
char *buf2;
int *arr;
/* 1. 分配普通内存 */
buf1 = (char *)os_malloc(128);
if (buf1)
{
os_kprintf("分配 128 字节成功,地址: %p\r\n", buf1);
/* 使用 buf1 ... */
}
/* 2. 分配对齐内存 */
buf2 = (char *)os_aligned_malloc(64, 256);
if (buf2)
{
os_kprintf("分配 64 字节对齐的 256 字节成功,地址: %p\r\n", buf2);
/* 使用 buf2 ... */
}
/* 3. 分配零初始化内存 */
arr = (int *)os_calloc(10, sizeof(int));
if (arr)
{
/* arr[0] ~ arr[9] 已被初始化为 0 */
os_kprintf("calloc 10 个 int 成功\r\n");
}
/* 4. 重分配内存 */
buf1 = (char *)os_realloc(buf1, 512);
if (buf1)
{
os_kprintf("重分配为 512 字节成功\r\n");
}
/* 5. 查看堆内存使用情况 */
os_default_heap_info(&info);
os_kprintf("堆: 总计=%lu 已用=%lu 峰值=%lu\r\n",
info.mem_total, info.mem_used, info.mem_maxused);
/* 6. 释放内存 */
os_free(buf1);
os_free(buf2);
os_free(arr);
/* 7. 检查堆完整性 */
if (os_default_heap_check() == OS_SUCCESS)
{
os_kprintf("堆完整性检查通过\r\n");
}
}五、多堆管理
除了默认堆,OneOS 还支持创建多个自定义堆实例,适用于需要将不同内存区域独立管理的场景(例如:将 SRAM 和 SDRAM 分别作为独立的堆来管理)。
5.1 静态定义堆
#define OS_HEAP_DEFINE(name) os_heap_dummy_t name- 功能:静态定义一个堆控制块变量
- 示例:
OS_HEAP_DEFINE(my_sdram_heap);定义一个名为my_sdram_heap的堆控制块
5.2 创建堆
os_heap_id os_heap_init(os_heap_dummy_t *heap_cb, const char *name);| 参数 | 类型 | 说明 |
|---|---|---|
heap_cb | os_heap_dummy_t * | 静态定义的堆控制块指针 |
name | const char * | 堆名称(用于调试和 Shell 显示) |
| 返回值 | 说明 |
|---|---|
os_heap_id | 堆实例 ID,非空表示成功 |
OS_NULL | 创建失败(堆已存在) |
5.3 添加内存区域
os_err_t os_heap_add(os_heap_id heap_id, void *start_addr, os_size_t size, enum os_mem_alg alg);参数与 os_default_heap_add 相同,但需要指定 heap_id。
5.4 多堆分配与释放
void *os_heap_alloc(os_heap_id heap_id, os_size_t size);
void *os_heap_aligned_alloc(os_heap_id heap_id, os_size_t align, os_size_t size);
void os_heap_free(os_heap_id heap_id, void *ptr);
void *os_heap_realloc(os_heap_id heap_id, void *ptr, os_size_t size);
void os_heap_info(os_heap_id heap_id, os_meminfo_t *info);
os_err_t os_heap_check(os_heap_id heap_id);这些 API 与默认堆 API 功能相同,但需要指定 heap_id 来操作特定的堆实例。
5.5 多堆使用示例
#include <os_memory.h>
/* 静态定义两个堆控制块 */
OS_HEAP_DEFINE(sram_heap_cb);
OS_HEAP_DEFINE(sdram_heap_cb);
static os_heap_id sram_heap_id;
static os_heap_id sdram_heap_id;
void multi_heap_init(void)
{
/* 创建 SRAM 堆 */
sram_heap_id = os_heap_init(&sram_heap_cb, "SRAM_HEAP");
os_heap_add(sram_heap_id, (void *)0x20000000, 64 * 1024, OS_MEM_ALG_FIRSTFIT);
/* 创建 SDRAM 堆 */
sdram_heap_id = os_heap_init(&sdram_heap_cb, "SDRAM_HEAP");
os_heap_add(sdram_heap_id, (void *)0xC0000000, 8 * 1024 * 1024, OS_MEM_ALG_BUDDY);
}
void multi_heap_task(void)
{
os_meminfo_t info;
char *fast_buf;
char *large_buf;
/* 从 SRAM 堆分配小块内存 */
fast_buf = (char *)os_heap_alloc(sram_heap_id, 256);
/* 从 SDRAM 堆分配大块内存 */
large_buf = (char *)os_heap_alloc(sdram_heap_id, 1024 * 1024);
/* 查看各堆使用情况 */
os_heap_info(sram_heap_id, &info);
os_kprintf("SRAM堆: 总计=%lu 已用=%lu 峰值=%lu\r\n",
info.mem_total, info.mem_used, info.mem_maxused);
os_heap_info(sdram_heap_id, &info);
os_kprintf("SDRAM堆: 总计=%lu 已用=%lu 峰值=%lu\r\n",
info.mem_total, info.mem_used, info.mem_maxused);
/* 释放内存 */
os_heap_free(sram_heap_id, fast_buf);
os_heap_free(sdram_heap_id, large_buf);
}六、Shell 命令
OneOS 提供了 Shell 命令用于调试堆内存:
| 命令 | 功能 | 说明 |
|---|---|---|
show_mem | 显示默认堆使用情况 | 包括总大小、已用、使用率、峰值、地址范围 |
show_heap | 显示所有堆信息 | 遍历所有已注册的堆实例 |
check_mem | 检查默认堆完整性 | 验证内存块结构一致性 |
📝 本节小结
- 默认堆 API(
os_malloc、os_free、os_realloc、os_calloc、os_aligned_malloc)易于使用,与标准 C 库风格一致 - 使用前需调用
os_default_heap_init()初始化,再通过os_default_heap_add()添加实际内存区域 - 多堆机制允许为不同内存区域(SRAM、SDRAM 等)创建独立堆实例,使用
OS_HEAP_DEFINE静态定义控制块 os_default_heap_info()/os_heap_info()可获取堆统计信息(总大小、已用、峰值)os_default_heap_check()/os_heap_check()用于堆完整性验证