1. CMA 概述:连续内存分配器的背景与价值
在 Linux 内核中,内存管理子系统长期面临一个核心矛盾:虚拟内存的灵活性与物理内存的连续性之间的冲突。多媒体驱动(Camera、GPU、VPU、Display)以及高性能 DMA 设备,通常要求分配数十 MB 甚至上百 MB 的物理连续大块内存。传统的 Buddy 分配器在系统长期运行后,由于频繁的分配与释放,物理内存页框被分割成大量离散的小块,形成严重的外部碎片,导致即使总空闲内存充足,也无法满足大块连续内存的分配请求。
CMA(Contiguous Memory Allocator)正是为解决这一矛盾而设计的。它允许系统在大部分时间内将预留的连续内存区域用于可移动页面的常规分配,仅在多媒体驱动或 DMA 设备真正需要时,通过页面迁移机制快速回收并整理出所需的连续物理内存块。这种“预留但不独占,按需回收”的设计哲学,使得系统既能享受虚拟内存的碎片容忍能力,又能在关键时刻提供硬件所需的连续物理内存。
1.1 内存碎片化:多媒体系统的隐形杀手
内存碎片化分为内部碎片和外部碎片。对于多媒体驱动而言,外部碎片是主要威胁。当系统经历长时间的应用程序启动、文件缓存、网络收发后,物理内存的页框分布会变得支离破碎。即使空闲页总数超过 100 MB,Buddy 分配器也可能无法找到一块连续的 8 MB 物理空间给 Camera 的 ISP 硬件使用。
| 碎片类型 | 产生原因 | 对多媒体驱动的影响 | CMA 的应对 |
|---|---|---|---|
| 内部碎片 | 分配粒度大于请求大小(如 Buddy 最小块 4KB) | 轻微,浪费少量内存 | 不直接处理,由 slab/slub 优化 |
| 外部碎片 | 频繁分配释放导致空闲页不连续 | 致命:无法分配大块 DMA 缓冲区 | 通过页面迁移整理出连续区域 |
1.2 CMA 在多媒体驱动中的关键作用
多媒体子系统是 CMA 最典型、最迫切的使用场景。以下设备通常依赖 CMA 提供连续物理内存:
- Camera (V4L2/ISP): 图像传感器输出 RAW 数据需要大块连续缓冲区用于 ISP 处理,通常 4~32 MB。
- GPU/Display: 帧缓冲(Framebuffer)和显示控制器要求物理连续内存,避免扫描输出时出现撕裂。
- Video Codec (VPU): 硬件编解码器需要连续内存存放参考帧和比特流缓冲区,4K/8K 场景下可达 64 MB。
- Audio DSP: 低延迟音频处理需要连续的 DMA 缓冲区,避免因 SG(Scatter-Gather)带来的额外延迟。
- Network Accelerator: 部分网卡硬件不支持 SG 模式,需要连续内存存放描述符和数据包。
1.3 CMA 与传统方案的对比优势
在 CMA 出现之前,嵌入式系统通常采用以下方案解决连续内存问题,但各有明显缺陷:
| 方案 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| 静态预留 | 在 bootargs 中预留大块内存,驱动独占 | 实现简单,分配可靠 | 内存浪费严重,系统可用内存减少 |
| IOMMU/SMMU | 硬件 IOMMU 将离散物理页映射为连续 IOVA | 无需物理连续,灵活性高 | 硬件成本高,增加 TLB 压力,延迟增加 |
| Scatter-Gather DMA | DMA 引擎支持链表描述符,处理非连续内存 | 无需连续内存 | 驱动复杂度高,部分硬件不支持,性能下降 |
| CMA | 预留区域 + 页面迁移 + 按需回收 | 兼顾内存利用率与连续性,透明 | 分配时可能触发页面迁移延迟 |
1.4 CMA 的工作流程概览
CMA 的完整生命周期包含以下关键步骤,理解这些步骤是后续章节深入分析的基础:
- 预留阶段:系统启动时,通过设备树
reserved-memory节点或内核参数cma=预留一段物理连续内存区域。 - 注册阶段:CMA 区域注册到内核的 CMA 框架中,关联对应的
cma结构体。 - 常规复用:在无多媒体分配请求时,CMA 区域内的页面被加入 Buddy 系统的
MIGRATE_CMA迁移类型中,供可移动页面使用。 - 分配触发:多媒体驱动调用
dma_alloc_coherent()或cma_alloc(),请求连续物理内存。 - 页面迁移:若 CMA 区域内存在非可移动页面,内核通过
alloc_contig_range()触发页面迁移,将页面逐页移出 CMA 区域。 - 分配完成:迁移完成后,CMA 区域变为连续空闲状态,分配器返回物理连续的内存给驱动。
- 释放回收:驱动使用完毕后调用
dma_free_coherent()或cma_release(),页面重新回到 CMA 区域,再次可供常规分配。
1.5 本章小结
CMA 是 Linux 内核中解决物理内存碎片化与大块连续内存需求之间矛盾的关键基础设施。它通过预留区域 + 页面迁移的机制,在保证内存利用率的同时,为多媒体驱动和 DMA 设备提供了可靠的连续内存分配能力。理解 CMA 的背景、解决的问题以及在多媒体栈中的核心位置,是后续深入学习其实现原理、配置优化和驱动集成的基础。
- 外部碎片是多媒体系统连续内存分配失败的主要原因。
- CMA 通过
MIGRATE_CMA迁移类型实现常规内存复用。 - 页面迁移是 CMA 分配的核心步骤,也是性能关键点。
- CMA 适用于 Camera、GPU、VPU、Display、Audio DSP 等多媒体设备。