Android匿名共享内存-Ashmem

什么是 Ashmem

Ashmem(Anonymous Shared Memory)是 Android 早期常用的跨进程共享内存机制。

它的核心目标是:

  • 在进程间共享同一块内存
  • 减少大数据在 IPC 过程中的重复拷贝
  • 让 Binder 只负责“控制信令 + 句柄传递”

为什么需要 Ashmem

Binder 很适合传输小对象、命令和控制信息,但不适合高频大数据块(例如图像帧、音频缓冲)。

典型组合方式是:

  • Binder:传 fd、偏移、长度、版本等元信息
  • Ashmem:承载真正的大块数据

核心模型

跨进程共享流程可以抽象成 4 步:

  1. 生产者创建 Ashmem 区域,得到 fd
  2. 生产者和消费者分别通过 mmap 映射该 fd
  3. 生产者写入、消费者读取同一块物理页
  4. 使用完毕后 munmap + close

补充:共享区容量按页对齐管理,协议中应显式区分:

  • region_size(映射总大小)
  • payload_len(当前有效数据长度)

这也是 Android 中常见的“控制面走 Binder,数据面走共享内存”设计。

基础调用链(Native)

常见的 Native 调用链路:

  • ashmem_create_region(name, size):创建共享区域
  • ashmem_set_prot_region(fd, PROT_READ/PROT_WRITE):设置访问权限
  • mmap(fd, size, ...):映射到用户态地址空间
  • munmap(addr, size):解除映射
  • close(fd):关闭句柄

补充:

  • 句柄本身可以通过 Binder 在进程间传递
  • 多进程读写同步需要业务层自己保证(锁、序号、状态位)

建议:

  • 生产者默认持有读写权限。
  • 消费者尽量映射为只读,减少误写风险。
  • 权限策略优先“最小可用权限”。

Java 层常见入口

历史上常见有两套:

  • MemoryFile:早期封装,常见于旧代码
  • SharedMemoryandroid.os.SharedMemory,API 27+):新一些的公开 API

在新项目里,优先考虑 SharedMemory 这类更明确、可维护性更好的接口。

与 Binder 的边界

可以把职责拆成两层:

  • Binder 负责:连接、权限、生命周期信令、错误上报
  • Ashmem 负责:大块数据共享

补充:Binder 传的是“fd能力”而不是裸内存地址。

  • 接收端拿到的是本进程可用的fd副本。
  • 发送端与接收端都应各自管理close时机,避免句柄泄漏。

好处是:

  • 减少 Binder 大对象传输压力
  • 降低序列化/反序列化成本
  • 在高频场景下更稳定

生命周期与内存语义(补充)

  • close(fd) 只关闭当前进程句柄,不代表其他进程映射立即失效
  • 映射是否可用取决于映射引用与底层对象生命周期
  • 设计时建议把“句柄生命周期”和“数据有效期”分开管理

补充:在ashmem语义里还要关注pin/unpin(可回收页)行为。

  • pin的区域在内存紧张时可能被系统回收。
  • 恢复访问时应校验数据完整性(如seq/checksum),避免把已失效内容当有效数据使用。

工程上常见做法:

  • 共享区头部放 magic/version/length/checksum
  • 用状态位区分 WRITING/READY/CONSUMED
  • 异常路径确保 munmapclose 成对释放

常见问题

  1. 并发写导致数据破坏

    多个写者同时写同一块内存而没有同步,容易出现脏读和结构体错位。

  2. 协议不一致

    发送端和接收端对字节结构理解不一致,导致解析崩溃或数据错乱。

  3. 泄漏与悬挂映射

    closemunmap,或者异常路径忘记释放,会造成内存与句柄泄漏。

  4. 无状态机导致读到半包

    建议在共享区头部固定字段:magic/version/state/seq/len/checksum,并约定状态流转:WRITING -> READY -> CONSUMED

方案对比

方案 优点 缺点 适用场景
Binder 直接传大对象 实现简单 拷贝/序列化开销大,受事务大小限制 小数据、低频
Ashmem + Binder 大数据效率高、拷贝少 需要自己管理同步和协议 图像帧、音视频缓冲
文件 mmap + IPC 通知 可持久化、便于离线 文件管理复杂,时延通常更高 落盘共享、离线分析

补充:

  • 图形链路(GPU纹理/合成)优先考虑BufferQueue/AHardwareBuffer
  • 通用大块字节共享场景再选Ashmem/SharedMemory

演进说明

在较新 Android 版本中,底层共享内存实现逐步向 memfd 方向演进(框架层可能做了兼容封装)。

但从业务层视角看,设计原则不变:

  • 控制信息与数据面分离
  • 共享内存做大数据承载
  • 明确同步协议与生命周期

小结

Ashmem本质是“共享内存 + fd 跨进程传递”的组合模型。

它不是为了替代 Binder,而是和 Binder 形成互补:

  • Binder 管控制
  • 共享内存管数据

在大数据、高频 IPC 的场景下,这种拆分通常更稳、更高效。


Android匿名共享内存-Ashmem
https://leo-wxy.github.io/2020/10/31/Android-匿名共享内存-Ashmem/
作者
Leo-Wxy
发布于
2020年10月31日
许可协议