Android匿名共享内存-Ashmem
什么是 Ashmem
Ashmem(Anonymous Shared Memory)是 Android 早期常用的跨进程共享内存机制。
它的核心目标是:
- 在进程间共享同一块内存
- 减少大数据在 IPC 过程中的重复拷贝
- 让 Binder 只负责“控制信令 + 句柄传递”
为什么需要 Ashmem
Binder 很适合传输小对象、命令和控制信息,但不适合高频大数据块(例如图像帧、音频缓冲)。
典型组合方式是:
Binder:传fd、偏移、长度、版本等元信息Ashmem:承载真正的大块数据
核心模型
跨进程共享流程可以抽象成 4 步:
- 生产者创建 Ashmem 区域,得到
fd - 生产者和消费者分别通过
mmap映射该fd - 生产者写入、消费者读取同一块物理页
- 使用完毕后
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:早期封装,常见于旧代码SharedMemory(android.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 - 异常路径确保
munmap与close成对释放
常见问题
并发写导致数据破坏
多个写者同时写同一块内存而没有同步,容易出现脏读和结构体错位。
协议不一致
发送端和接收端对字节结构理解不一致,导致解析崩溃或数据错乱。
泄漏与悬挂映射
只
close不munmap,或者异常路径忘记释放,会造成内存与句柄泄漏。无状态机导致读到半包
建议在共享区头部固定字段:
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/