内存管理
2026/7/16大约 8 分钟内核组件内核内存管理堆内存内存池
内存管理
📚 本节导读
学习时长: 约 15 分钟
难度级别: ⭐⭐☆☆☆
前置知识: C 语言内存模型、基本数据结构和链表
内存管理是操作系统的核心功能之一。OneOS 提供了两套互补的内存管理机制:堆内存管理(动态分配)和内存池(固定大小块分配),能够满足从灵活的动态内存分配到确定性实时分配的各种场景需求。
🎯 学习目标
- 理解 OneOS 内存管理的两大分类:堆内存与内存池
- 掌握内存管理模块的配置依赖关系
- 了解内存算法选择:FIRSTFIT 与 BUDDY
- 熟悉内存信息结构体
os_meminfo_t - 建立整体知识框架,为后续深入各子模块做好准备
一、内存管理总览
1.1 两大核心机制
OneOS 的内存管理分为两大类别,分别适用于不同的使用场景:
┌──────────────────────────────────────────────────────────────────┐
│ OneOS 内存管理体系 │
│ │
│ ┌─────────────────────┐ ┌─────────────────────────────┐ │
│ │ 堆内存管理 │ │ 内存池 │ │
│ │ (Heap Memory) │ │ (Memory Pool) │ │
│ ├─────────────────────┤ ├─────────────────────────────┤ │
│ │ • 动态分配任意大小 │ │ • 固定大小块分配 │ │
│ │ • 灵活但非确定性 │ │ • 确定性分配时间 │ │
│ │ • 支持两种算法 │ │ • 无碎片问题 │ │
│ │ • 支持多堆实例 │ │ • 支持超时等待 │ │
│ │ • 支持内存追踪 │ │ • 支持溢出检测 │ │
│ └─────────────────────┘ └─────────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ FIRSTFIT 算法 │ │ 内存块 (Block) │ │
│ │ BUDDY 算法 │ │ 内存追踪 │ │
│ └─────────────────┘ └─────────────────┘ │
└──────────────────────────────────────────────────────────────────┘| 特性 | 堆内存(Heap) | 内存池(Memory Pool) |
|---|---|---|
| 分配粒度 | 任意大小(字节级) | 固定大小块 |
| 分配时间 | 非确定性 | 确定性(O(1)) |
| 碎片问题 | 存在外部/内部碎片 | 无碎片 |
| 适用场景 | 通用动态分配 | 高频、固定大小的对象分配 |
| 并发安全 | 通过信号量保护 | 通过自旋锁保护 |
| 超时等待 | 不支持 | 支持 |
1.2 配置依赖关系
/* 以下宏定义在 oneos_config.h 中配置 */
#define OS_USING_HEAP /* 启用堆内存管理 */
#define OS_USING_MEM_POOL /* 启用内存池管理 */
/* 堆内存依赖信号量,当启用 OS_USING_HEAP 时必须启用 OS_USING_SEMAPHORE */
/* 内存算法至少选择一种 */
#define OS_USING_ALG_FIRSTFIT /* 选择 FIRSTFIT 算法 */
#define OS_USING_ALG_BUDDY /* 选择 BUDDY 算法 */
/* 可选功能 */
#define OS_USING_MEMPOOL_CHECK_TAG /* 内存池溢出检测 */
#define OS_USING_MEM_TRACE /* 内存追踪 */依赖关系图:
OS_USING_HEAP
├── OS_USING_SEMAPHORE (必须)
├── OS_USING_ALG_FIRSTFIT (至少选一种)
└── OS_USING_ALG_BUDDY (至少选一种)
└── OS_USING_MEM_TRACE (可选)
OS_USING_MEM_POOL
└── OS_USING_MEMPOOL_CHECK_TAG (可选)二、内存信息结构体
2.1 os_meminfo_t
堆内存信息结构体定义在 kernel/include/os_memory.h 中:
来源:kernel/include/os_memory.h
struct os_meminfo
{
os_size_t mem_total;
os_size_t mem_used;
os_size_t mem_maxused;
};
typedef struct os_meminfo os_meminfo_t;字段说明:
| 字段 | 类型 | 含义 |
|---|---|---|
mem_total | os_size_t | 堆内存区域的总字节数 |
mem_used | os_size_t | 当前已分配且在使用的字节数 |
mem_maxused | os_size_t | 自初始化以来,内存使用的峰值(字节) |
概念对应表:
| 堆内存概念 | 对应字段 |
|---|---|
| 内存区域大小 | mem_total |
| 当前占用 | mem_used |
| 历史峰值(泄漏检测/内存监控) | mem_maxused |
使用示例:
os_meminfo_t info;
os_default_heap_info(&info);
os_kprintf("堆内存: 总计=%lu, 已用=%lu, 峰值=%lu\r\n",
info.mem_total, info.mem_used, info.mem_maxused);2.2 os_mpinfo_t
内存池信息结构体,用于获取内存池的统计信息:
来源:kernel/include/os_memory.h
struct os_mpinfo
{
os_size_t blk_size; /* Size can be used for users in one memory block. */
os_size_t blk_total_num; /* Numbers of memory block. */
os_size_t blk_free_num; /* Numbers of free memory block. */
};
typedef struct os_mpinfo os_mpinfo_t;字段说明:
| 字段 | 类型 | 含义 |
|---|---|---|
blk_size | os_size_t | 单个内存块中用户可用的字节数 |
blk_total_num | os_size_t | 内存块总数量 |
blk_free_num | os_size_t | 当前空闲的内存块数量 |
概念对应表:
| 内存池概念 | 对应字段 |
|---|---|
| 单个块可用大小 | blk_size |
| 总块数 | blk_total_num |
| 空闲块数 | blk_free_num |
三、选型指南
3.1 何时使用堆内存(Heap)
堆内存支持动态分配任意大小的内存,灵活但分配时间不确定:
- 对象大小变化不定:任务运行时才知道需要多大的内存(如变长缓冲区)。
- 通用动态分配:需要 malloc/free 风格的内存管理。
- 对分配时间不敏感:允许 O(1) 之外的非确定性分配耗时。
- 需要多堆隔离:不同子系统使用独立的堆实例,避免相互影响。
3.2 何时使用内存池(Memory Pool)
内存池分配固定大小的内存块,分配时间确定(O(1)),无碎片:
- 对象大小固定:如固定长度的消息结构、任务控制块、DMA 缓冲区。
- 高频分配/释放:需要确定性、低开销的分配。
- 实时性要求高:分配时间可预期,不能接受堆的非确定性。
- 需要溢出检测:内存池支持
OS_USING_MEMPOOL_CHECK_TAG溢出检测,可排查越界。
3.3 选择 FIRSTFIT 还是 BUDDY 算法(堆内存)
| 维度 | FIRSTFIT | BUDDY |
|---|---|---|
| 原理 | 从空闲链表头扫描,取第一个足够大的块 | 按 2 的幂次方分级,伙伴块可合并 |
| 配置宏 | OS_USING_ALG_FIRSTFIT | OS_USING_ALG_BUDDY |
| 优点 | 分配快、实现简单、内存利用率较高 | 减少外部碎片、合并快、适合频繁分配释放 |
| 缺点 | 长时间运行可能产生外部碎片 | 存在内部碎片(非 2 的幂次方请求被向上取整) |
| 适用 | 通用嵌入式,分配模式多样化 | 频繁分配/释放、对碎片敏感 |
3.4 选型快速决策流程
你的需求是什么?
│
├── 需要分配的内存块大小是否固定?
│ ├── 是 ────────────────────────────────► 用【内存池】
│ │ (固定大小块,O(1) 确定性分配,无碎片)
│ │
│ └── 否(大小不定)─────────────────────► 用【堆内存】
│ ├── 对碎片是否敏感、是否频繁分配/释放?
│ │ ├── 是 ────────────────────► 用 BUDDY 算法
│ │ └── 否 ────────────────────► 用 FIRSTFIT 算法
│ └── 需要多个独立堆实例?
│ └── 是 ────────────────────► 多堆管理(见 4.4.1)
│
└── 需要内存泄漏追踪/完整性检查?
└── 是 ────────────────────────────────► 启用 OS_USING_MEM_TRACE3.5 一句话速记
| 场景 | 首选机制 |
|---|---|
| 大小固定、高频、要确定性 | 内存池 |
| 大小可变、通用分配 | 堆内存 |
| 频繁分配/释放、碎片敏感 | 堆 + BUDDY |
| 通用多样化分配 | 堆 + FIRSTFIT |
| 需要泄漏检测 | 堆 + MEM_TRACE |
| 需要越界检测 | 内存池 + CHECK_TAG |
注意:在
kernel/include/os_memory.h中,如果定义了OS_USING_HEAP,则必须至少选择一种算法(OS_USING_ALG_FIRSTFIT或OS_USING_ALG_BUDDY),否则会触发编译错误。
四、模块共性概念
4.1 静态 / 动态对象
堆内存和内存池都支持静态(用户提供内存) 和动态(内核从堆分配) 两种创建方式:
| 对象 | 静态创建 | 动态创建 |
|---|---|---|
| 堆内存 | 用户提供堆空间(os_heap_create_static) | 内核分配(os_heap_create_dynamic) |
| 内存池 | 用户提供内存池(os_mp_create_static) | 内核分配(os_mp_create_dynamic) |
- 静态创建:控制块由用户定义(
OS_*_DEFINE宏),不依赖OS_USING_HEAP,需防重复创建。 - 动态创建:控制块由
OS_KERNEL_MALLOC分配,需要OS_USING_HEAP,失败时返回OS_NULL。
4.2 内存碎片问题
| 碎片类型 | 定义 | 哪种机制避免 |
|---|---|---|
| 外部碎片 | 空闲块分散不连续,无法满足大块请求 | 内存池(无) / BUDDY(合并) |
| 内部碎片 | 分配块比请求大,浪费内部空间 | FIRSTFIT(较少) / BUDDY(明显,向上取整) |
4.3 超时等待与确定性
| 特性 | 堆内存 | 内存池 |
|---|---|---|
| 内存不足时是否等待 | 否(返回 OS_NULL) | 是(支持 timeout 超时等待) |
| 分配时间确定性 | 非确定(FIRSTFIT 扫描) | O(1) 确定性 |
| 并发保护 | 信号量 | 自旋锁 |
4.4 模块配置依赖(汇总)
OS_USING_HEAP → 需 OS_USING_SEMAPHORE + 至少一种算法
├── OS_USING_ALG_FIRSTFIT
└── OS_USING_ALG_BUDDY
└── OS_USING_MEM_TRACE(可选,追踪)
OS_USING_MEM_POOL → 独立模块
└── OS_USING_MEMPOOL_CHECK_TAG(可选,溢出检测)五、子章节导航
内存管理模块包含以下子章节,建议按顺序阅读:
| 章节 | 标题 | 核心内容 |
|---|---|---|
| 4.4.1 | 堆内存管理 | 默认堆与多堆的创建、分配/释放、信息查询 API 详解 |
| 4.4.2 | FIRSTFIT 算法 | 首次适应算法原理与实现 |
| 4.4.3 | BUDDY 算法 | 伙伴系统算法原理与实现 |
| 4.4.4 | 内存池 | 固定大小块内存池的创建、申请/释放 API 详解(含块布局、溢出检测) |
| 4.4.5 | 内存追踪 | 内存泄漏检测与完整性检查 |
📝 本节小结
核心要点回顾
本节是内存管理模块的总览页,核心要点如下:
1. 两大核心机制
| 机制 | 分配粒度 | 分配时间 | 碎片 | 适用 |
|---|---|---|---|---|
| 堆内存(Heap) | 任意大小 | 非确定性 | 有 | 通用动态分配 |
| 内存池(Pool) | 固定大小块 | O(1) 确定性 | 无 | 高频固定大小对象 |
2. 配置依赖
OS_USING_HEAP依赖OS_USING_SEMAPHORE,且必须至少选一种算法(FIRSTFIT/BUDDY)。- 内存池是独立模块(
OS_USING_MEM_POOL),可选OS_USING_MEMPOOL_CHECK_TAG溢出检测。
3. 算法选择
- FIRSTFIT:简单、内存利用率较高,但长期运行可能产生外部碎片。
- BUDDY:减少外部碎片、合并快,适合频繁分配/释放,但有内部碎片。
4. 信息结构体
os_meminfo_t:堆内存统计(总大小/已用/峰值)。os_mpinfo_t:内存池统计(块大小/总块数/空闲块数)。
关键易错点速查
| 易错点 | 正确做法 |
|---|---|
定义了 OS_USING_HEAP 却未选算法 | 必须选 FIRSTFIT 或 BUDDY,否则编译错误 |
| 用堆做高频固定大小分配 | 改用内存池(确定性、无碎片) |
内存不足时堆返回 OS_NULL 未检查 | 必须检查返回值,否则解引用空指针 |
内存池申请用 OS_NO_WAIT 会失败 | 内存池满时不等待则申请失败,需处理或等待 |
忽略 mem_maxused 峰值 | 用峰值监控内存增长、评估堆大小 |
| 混淆两个信息结构体 | os_meminfo_t 管堆,os_mpinfo_t 管内存池 |
下一步
本节为内存管理模块导航总览。接下来请深入学习第一个子章节:
- 4.4.1 堆内存管理:掌握默认堆与多堆的创建、分配/释放 API 详解