3. Buffer管理基础:Gralloc Buffer分配、生命周期与引用计数机制
在Camera HAL Pipeline中,Buffer是承载图像数据的核心载体。Gralloc作为Android图形内存分配器,负责管理Buffer的分配、映射、共享与回收。理解Gralloc Buffer的生命周期与引用计数机制,是优化数据传输、避免内存泄漏与帧率抖动的关键前提。
3.1 Gralloc Buffer分配流程
Gralloc Buffer的分配涉及HAL层与内核驱动层的协作。分配请求通常由Camera HAL的Stream消费者(如Surface)发起,经过Gralloc HAL模块完成物理内存分配与CPU/GPU映射。
3.1.1 分配接口与流程
Gralloc分配的核心接口为 alloc() 或 allocate(),其典型调用链如下:
- BufferQueue生产者请求:Camera HAL通过
dequeueBuffer()向BufferQueue申请空闲Buffer。 - Gralloc分配触发:若BufferQueue中无可用Buffer,则调用Gralloc的
alloc()分配新Buffer。 - 内存分配:Gralloc HAL根据使用标志选择分配器(ION、DMA-BUF、System Heap),分配连续或非连续物理内存。
- 映射与句柄生成:分配完成后,返回
buffer_handle_t句柄,并完成CPU/GPU地址映射。 - Buffer入队:新分配的Buffer加入BufferQueue的空闲队列,等待Camera HAL填充数据。
3.1.2 分配参数对比表
| 参数 | 说明 | 典型值 | 性能影响 |
|---|---|---|---|
| width / height | 图像分辨率 | 1920x1080 | 直接影响内存大小与分配耗时 |
| format | 像素格式 | HAL_PIXEL_FORMAT_YCbCr_420_SP | 决定内存布局与对齐要求 |
| usage | 使用标志位组合 | GRALLOC_USAGE_HW_CAMERA_WRITE | 影响内存类型与映射方式 |
| layerCount | 平面数 | 1(单平面)或 2(双平面) | 多平面增加映射复杂度 |
3.2 Buffer生命周期管理
Gralloc Buffer的生命周期从分配开始,到释放结束,中间经历多个状态转换。理解这些状态是正确管理Buffer引用计数的前提。
3.2.1 生命周期状态机
以下SVG图展示了Gralloc Buffer在Camera HAL Pipeline中的典型生命周期状态转换:
3.2.2 生命周期关键阶段说明
| 阶段 | 描述 | 引用计数变化 |
|---|---|---|
| FREE | Buffer在BufferQueue空闲队列中等待使用 | refcount = 0 |
| DEQUEUED | 生产者(Camera HAL)获取Buffer用于填充数据 | refcount = 1(生产者持有) |
| QUEUED | 生产者填充完成,Buffer入队等待消费者处理 | refcount = 1(BufferQueue持有) |
| ACQUIRED | 消费者(如Display、Encoder)获取Buffer进行读取 | refcount = 1(消费者持有) |
| RELEASED | 消费者处理完成,Buffer释放回BufferQueue | refcount = 0 |
| ALLOCATED | Buffer已分配内存但尚未加入BufferQueue | refcount = 0(仅分配) |
3.3 引用计数机制
Gralloc Buffer的引用计数(refcount)是确保Buffer在多个消费者之间安全共享的核心机制。每个Buffer内部维护一个原子计数器,记录当前持有该Buffer的实体数量。
3.3.1 引用计数增减规则
- 增加引用:当生产者调用
dequeueBuffer()或消费者调用acquireBuffer()时,Buffer的引用计数加1。 - 减少引用:当生产者调用
cancelBuffer()或消费者调用releaseBuffer()时,引用计数减1。 - 零引用释放:当引用计数降为0时,Buffer被回收到空闲池,或根据策略释放物理内存。
cancelBuffer() 或 queueBuffer(),会导致Buffer引用计数泄漏,最终耗尽Buffer池,造成预览或录像卡顿。务必在异常路径中确保Buffer被正确归还。
3.3.2 引用计数与Buffer共享
在Camera HAL Pipeline中,同一个Buffer可能被多个消费者共享(如预览与编码同时使用)。此时引用计数机制确保Buffer在所有消费者都释放后才被回收。
以下SVG图展示了多消费者场景下的引用计数变化:
3.4 引用计数与内存泄漏防范
在Camera HAL开发中,引用计数管理不当是导致内存泄漏的主要原因之一。以下是一些最佳实践:
- 配对调用:确保每个
dequeueBuffer()都有对应的queueBuffer()或cancelBuffer()。 - 异常处理:在错误路径中显式调用
cancelBuffer()归还Buffer。 - 使用智能指针:在HAL实现中使用
sp<GraphicBuffer>自动管理引用计数。 - 监控工具:利用
dumpsys或procrank监控Buffer分配与泄漏情况。
__sync_fetch_and_add)更新引用计数。
3.5 本章小结
Gralloc Buffer管理是Camera HAL Pipeline数据传输优化的基础。通过理解Buffer的分配流程、生命周期状态转换以及引用计数机制,开发者可以避免常见的内存泄漏与帧率抖动问题。在实际优化中,应重点关注Buffer预分配策略、引用计数配对调用以及多消费者共享场景下的计数管理。