news 2026/5/1 11:01:07

【OpenHarmony】匿名共享内存模块详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【OpenHarmony】匿名共享内存模块详解

匿名共享内存模块详解

🧠一句话概括:Ashmem(匿名共享内存)就像"进程间的公共黑板",多个进程可以同时读写同一块内存。


📚 目录

  1. 什么是匿名共享内存?
  2. 为什么需要 Ashmem?
  3. Ashmem 工作原理
  4. Ashmem 类详解
  5. 核心操作流程
  6. 使用示例
  7. 保护标志详解
  8. 最佳实践

1. 什么是匿名共享内存?

1.1 通俗理解

想象一个办公室场景 🏢:

普通内存

每个员工有自己的便签本 员工A:写在自己的便签上 员工B:看不到员工A写的内容 要传递信息 → 需要复制便签

共享内存

办公室有一块公共白板 📋 员工A:在白板上写内容 员工B:直接看白板上的内容 无需复制 → 直接共享!

1.2 技术定义

Ashmem(Anonymous Shared Memory)是 Android/Linux 系统提供的匿名共享内存机制:

  • 📁基于文件描述符:通过 fd 访问
  • 🔄跨进程共享:多个进程可以映射同一块内存
  • 🧹自动回收:当所有引用关闭时自动释放
进程B
内核空间
进程A
映射区域B
用户空间B
Ashmem 区域
/dev/ashmem
映射区域A
用户空间A

2. 为什么需要 Ashmem?

2.1 进程间通信的挑战

进程隔离
无法直接访问
进程A 内存空间
进程B 内存空间

问题:每个进程有独立的内存空间,无法直接访问其他进程的内存。

2.2 传统 IPC 方式的问题

方式问题
管道/Socket需要数据复制,大数据量效率低
消息队列有大小限制,需要序列化
信号只能传递简单信息

2.3 Ashmem 的优势

Ashmem
映射
映射
共享内存
进程A
进程B
0次数据复制
传统IPC
复制数据
复制数据
内核缓冲区
进程A
进程B
2次数据复制
优势说明
零拷贝数据无需复制,直接共享
高效适合大数据量传输
灵活可以设置保护标志
安全支持权限控制

3. Ashmem 工作原理

3.1 整体架构

内核空间
用户空间
open/ioctl/mmap
dev/ashmem
Ashmem 驱动
物理内存
应用程序
Ashmem 类

3.2 关键步骤

应用程序Ashmem类内核物理内存CreateAshmem("name", size)open("/dev/ashmem")返回 fdioctl(SET_NAME)ioctl(SET_SIZE)MapReadAndWriteAshmem()mmap(fd, size)分配物理内存返回映射地址WriteToAshmem(data)直接写入ReadFromAshmem()直接读取UnmapAshmem()munmap()CloseAshmem()close(fd)应用程序Ashmem类内核物理内存

4. Ashmem 类详解

4.1 类结构

«基类»
RefBase
Ashmem
-int memoryFd_
-int32_t memorySize_
-int flag_
-void* startAddr_
+CreateAshmem(name, size)
+Ashmem(fd, size)
+~Ashmem()
+GetAshmemFd() : int
+SetProtection(type) : bool
+GetProtection() : int
+GetAshmemSize() : int32_t
+CloseAshmem() : void
+MapAshmem(mapType) : bool
+MapReadAndWriteAshmem() : bool
+MapReadOnlyAshmem() : bool
+UnmapAshmem() : void
+WriteToAshmem(data, size, offset) : bool
+ReadFromAshmem(size, offset)
-CheckValid(size, offset, cmd) : bool

4.2 成员变量

成员类型说明
memoryFd_int文件描述符
memorySize_int32_t内存区域大小
flag_int用户空间保护标志
startAddr_void*映射后的起始地址

4.3 核心方法

创建 Ashmem
// 静态工厂方法staticsptr<Ashmem>CreateAshmem(constchar*name,int32_tsize);
CreateAshmem
参数有效?
返回 nullptr
AshmemCreate
open /dev/ashmem
ioctl SET_NAME
ioctl SET_SIZE
成功?
new Ashmem
返回 sptr
映射内存
boolMapAshmem(intmapType);// 通用映射boolMapReadAndWriteAshmem();// 读写映射boolMapReadOnlyAshmem();// 只读映射voidUnmapAshmem();// 取消映射
flowchart LR subgraph 映射类型 A[MapAshmem<br/>PROT_READ] --> R[只读] B[MapAshmem<br/>PROT_WRITE] --> W[只写] C[MapAshmem<br/>PROT_READ|PROT_WRITE] --> RW[读写] end
读写数据
boolWriteToAshmem(constvoid*data,int32_tsize,int32_toffset);constvoid*ReadFromAshmem(int32_tsize,int32_toffset);
ReadFromAshmem
有效?
检查参数
返回 nullptr
检查权限
有读权限?
返回地址指针
WriteToAshmem
有效?
检查参数
返回 false
检查权限
有写权限?
memcpy 写入
返回 true

5. 核心操作流程

5.1 完整生命周期

CreateAshmem()
MapAshmem()
Read/Write
UnmapAshmem()
MapAshmem()
CloseAshmem()
CloseAshmem()
Created
Mapped
Unmapped
Closed

5.2 内存布局

Ashmem 内存区域: ┌────────────────────────────────────────────────────────┐ │ memorySize_ 字节 │ ├────────────────────────────────────────────────────────┤ │ startAddr_ │ │ ↓ │ │ ┌──────┬──────┬──────┬──────┬──────┬──────────────────┐│ │ │ │ │ │ │ │ ││ │ │ 数据1 │ 数据2 │ 数据3 │ ... │ 数据N │ 空闲空间 ││ │ │ │ │ │ │ │ ││ │ └──────┴──────┴──────┴──────┴──────┴──────────────────┘│ │ ↑ ↑ │ │ offset=0 offset=n │ └────────────────────────────────────────────────────────┘

5.3 跨进程共享流程

进程ABinder/IPC进程BCreateAshmem("shared", 1024)MapReadAndWriteAshmem()WriteToAshmem(data)传递 fd接收 fdnew Ashmem(fd, size)MapReadOnlyAshmem()ReadFromAshmem()两个进程共享同一块内存!进程ABinder/IPC进程B

6. 使用示例

6.1 基本用法

#include"ashmem.h"#include<iostream>#include<cstring>usingnamespaceOHOS;voidBasicAshmemDemo(){// 1. 创建 Ashmem 区域sptr<Ashmem>ashmem=Ashmem::CreateAshmem("MySharedMem",1024);if(ashmem==nullptr){std::cerr<<"创建 Ashmem 失败"<<std::endl;return;}std::cout<<"Ashmem FD: "<<ashmem->GetAshmemFd()<<std::endl;std::cout<<"Ashmem Size: "<<ashmem->GetAshmemSize()<<std::endl;// 2. 映射到用户空间(读写模式)if(!ashmem->MapReadAndWriteAshmem()){std::cerr<<"映射失败"<<std::endl;return;}// 3. 写入数据constchar*message="Hello, Ashmem!";if(ashmem->WriteToAshmem(message,strlen(message)+1,0)){std::cout<<"写入成功"<<std::endl;}// 4. 读取数据constchar*readData=static_cast<constchar*>(ashmem->ReadFromAshmem(strlen(message)+1,0));if(readData){std::cout<<"读取到: "<<readData<<std::endl;}// 5. 取消映射ashmem->UnmapAshmem();// 6. 关闭(析构时也会自动关闭)ashmem->CloseAshmem();}

6.2 写入结构体

#include"ashmem.h"structUserData{intid;charname[32];doublescore;};voidWriteStructDemo(){sptr<Ashmem>ashmem=Ashmem::CreateAshmem("UserData",sizeof(UserData)*10);ashmem->MapReadAndWriteAshmem();// 写入多个结构体for(inti=0;i<10;i++){UserData user;user.id=i+1;snprintf(user.name,sizeof(user.name),"User%d",i+1);user.score=80.0+i*2;intoffset=i*sizeof(UserData);ashmem->WriteToAshmem(&user,sizeof(UserData),offset);}// 读取第 5 个用户intreadOffset=4*sizeof(UserData);constUserData*user5=static_cast<constUserData*>(ashmem->ReadFromAshmem(sizeof(UserData),readOffset));if(user5){std::cout<<"ID: "<<user5->id<<std::endl;std::cout<<"Name: "<<user5->name<<std::endl;std::cout<<"Score: "<<user5->score<<std::endl;}ashmem->UnmapAshmem();ashmem->CloseAshmem();}

6.3 跨进程共享示例

进程 A(生产者)
#include"ashmem.h"#include<unistd.h>voidProducerProcess(){// 创建共享内存sptr<Ashmem>ashmem=Ashmem::CreateAshmem("SharedBuffer",4096);ashmem->MapReadAndWriteAshmem();intfd=ashmem->GetAshmemFd();intsize=ashmem->GetAshmemSize();// 通过某种 IPC 方式(如 Binder)将 fd 和 size 传递给进程 B// SendToProcessB(fd, size);// 写入数据intcounter=0;while(true){charbuffer[64];snprintf(buffer,sizeof(buffer),"Message #%d",++counter);ashmem->WriteToAshmem(buffer,strlen(buffer)+1,0);std::cout<<"生产者写入: "<<buffer<<std::endl;sleep(1);}}
进程 B(消费者)
#include"ashmem.h"#include<unistd.h>voidConsumerProcess(intfd,intsize){// 使用从进程 A 获取的 fd 创建 Ashmemsptr<Ashmem>ashmem=newAshmem(fd,size);// 只读映射ashmem->MapReadOnlyAshmem();// 读取数据while(true){constchar*data=static_cast<constchar*>(ashmem->ReadFromAshmem(64,0));if(data){std::cout<<"消费者读取: "<<data<<std::endl;}sleep(1);}}

6.4 环形缓冲区实现

#include"ashmem.h"#include<atomic>classSharedRingBuffer{public:staticconstexprintBUFFER_SIZE=4096;staticconstexprintHEADER_SIZE=sizeof(int)*2;// head + tailSharedRingBuffer(constchar*name){ashmem_=Ashmem::CreateAshmem(name,BUFFER_SIZE+HEADER_SIZE);ashmem_->MapReadAndWriteAshmem();// 初始化头尾指针intzero=0;ashmem_->WriteToAshmem(&zero,sizeof(int),0);// headashmem_->WriteToAshmem(&zero,sizeof(int),sizeof(int));// tail}boolWrite(constvoid*data,intsize){int*head=(int*)ashmem_->ReadFromAshmem(sizeof(int),0);int*tail=(int*)ashmem_->ReadFromAshmem(sizeof(int),sizeof(int));intavailable=(BUFFER_SIZE+*head-*tail)%BUFFER_SIZE;if(size>available){returnfalse;// 缓冲区满}intwritePos=HEADER_SIZE+*tail;ashmem_->WriteToAshmem(data,size,writePos);intnewTail=(*tail+size)%BUFFER_SIZE;ashmem_->WriteToAshmem(&newTail,sizeof(int),sizeof(int));returntrue;}intRead(void*buffer,intmaxSize){int*head=(int*)ashmem_->ReadFromAshmem(sizeof(int),0);int*tail=(int*)ashmem_->ReadFromAshmem(sizeof(int),sizeof(int));intavailable=(*tail-*head+BUFFER_SIZE)%BUFFER_SIZE;intreadSize=std::min(available,maxSize);if(readSize==0){return0;}intreadPos=HEADER_SIZE+*head;constvoid*data=ashmem_->ReadFromAshmem(readSize,readPos);memcpy(buffer,data,readSize);intnewHead=(*head+readSize)%BUFFER_SIZE;ashmem_->WriteToAshmem(&newHead,sizeof(int),0);returnreadSize;}~SharedRingBuffer(){ashmem_->UnmapAshmem();ashmem_->CloseAshmem();}private:sptr<Ashmem>ashmem_;};

7. 保护标志详解

7.1 保护标志类型

// Linux 内存保护标志#definePROT_NONE0x0// 不可访问#definePROT_READ0x1// 可读#definePROT_WRITE0x2// 可写#definePROT_EXEC0x4// 可执行

7.2 两层保护机制

flowchart TB subgraph 内核层保护 K[SetProtection] K --> KR[PROT_READ] K --> KW[PROT_WRITE] K --> KRW[PROT_READ|PROT_WRITE] end subgraph 用户空间保护 U[MapAshmem] U --> UR[PROT_READ] U --> UW[PROT_WRITE] U --> URW[PROT_READ|PROT_WRITE] end KRW --> URW KRW --> UR KR --> UR Note1[用户空间权限 ≤ 内核层权限]

7.3 权限组合

内核层用户空间结果
READREAD✅ 可读
READWRITE❌ 写入失败
WRITEWRITE✅ 可写
WRITEREAD❌ 读取失败
READ|WRITEREAD✅ 可读
READ|WRITEWRITE✅ 可写
READ|WRITEREAD|WRITE✅ 可读写

7.4 设置保护标志

sptr<Ashmem>ashmem=Ashmem::CreateAshmem("Protected",1024);// 设置内核层保护(只读)ashmem->SetProtection(PROT_READ);// 尝试读写映射 - 会失败,因为内核层只允许读boolsuccess=ashmem->MapReadAndWriteAshmem();// false// 只读映射 - 成功success=ashmem->MapReadOnlyAshmem();// true// 获取当前保护标志intprot=ashmem->GetProtection();// PROT_READ

8. 最佳实践

8.1 使用建议

✅ 推荐做法
// 1. 使用智能指针管理sptr<Ashmem>ashmem=Ashmem::CreateAshmem("name",size);// 2. 检查创建结果if(ashmem==nullptr){// 处理错误}// 3. 检查映射结果if(!ashmem->MapReadAndWriteAshmem()){// 处理错误}// 4. 检查读写结果if(!ashmem->WriteToAshmem(data,size,offset)){// 处理错误}// 5. 使用完毕后取消映射ashmem->UnmapAshmem();// 6. 根据需要设置合适的保护标志ashmem->SetProtection(PROT_READ);// 只读共享
❌ 避免的错误
// 错误1: 不检查返回值sptr<Ashmem>ashmem=Ashmem::CreateAshmem("name",-1);// size 无效ashmem->MapReadAndWriteAshmem();// ❌ ashmem 为 nullptr// 错误2: 越界访问ashmem->WriteToAshmem(data,1024,900);// ❌ 900 + 1024 > size// 错误3: 权限不匹配ashmem->SetProtection(PROT_READ);ashmem->MapReadAndWriteAshmem();// ❌ 映射失败// 错误4: 未映射就读写sptr<Ashmem>ashmem=Ashmem::CreateAshmem("name",1024);ashmem->WriteToAshmem(data,size,0);// ❌ 未映射// 错误5: 重复映射ashmem->MapReadAndWriteAshmem();ashmem->MapReadOnlyAshmem();// ❌ 应该先 UnmapAshmem

8.2 性能优化

场景建议
大数据量使用 Ashmem 避免复制
频繁读写保持映射状态,避免反复 map/unmap
多进程读使用只读映射,提高安全性
对齐访问按 4 字节或 8 字节对齐,提高效率

8.3 安全建议

安全建议
最小权限原则
边界检查
同步机制
只读进程用 PROT_READ
写入进程用 PROT_WRITE
检查 offset + size <= memorySize
检查返回值
多进程写入需要同步
使用互斥锁或信号量

8.4 调试技巧

// 打印 Ashmem 状态voidDebugAshmem(constsptr<Ashmem>&ashmem){std::cout<<"=== Ashmem Debug ==="<<std::endl;std::cout<<"FD: "<<ashmem->GetAshmemFd()<<std::endl;std::cout<<"Size: "<<ashmem->GetAshmemSize()<<std::endl;std::cout<<"Protection: "<<ashmem->GetProtection()<<std::endl;}// 检查系统 Ashmem 使用情况// cat /proc/ashmem (如果可用)

📊 API 速查表

全局函数

函数说明返回值
AshmemCreate(name, size)创建 Ashmem 区域fd
AshmemSetProt(fd, prot)设置保护标志0 成功,-1 失败
AshmemGetSize(fd)获取大小size

Ashmem 类

方法说明返回值
CreateAshmem(name, size)创建 Ashmemsptr
GetAshmemFd()获取文件描述符int
GetAshmemSize()获取大小int32_t
SetProtection(type)设置保护标志bool
GetProtection()获取保护标志int
MapAshmem(mapType)映射内存bool
MapReadAndWriteAshmem()读写映射bool
MapReadOnlyAshmem()只读映射bool
UnmapAshmem()取消映射void
WriteToAshmem(data, size, offset)写入数据bool
ReadFromAshmem(size, offset)读取数据void*
CloseAshmem()关闭void

保护标志

标志说明
PROT_NONE0x0不可访问
PROT_READ0x1可读
PROT_WRITE0x2可写
PROT_EXEC0x4可执行

🎯 总结

记住这三点

  1. 先创建,再映射,才能读写
  2. 用户空间权限 ≤ 内核层权限
  3. 多进程写入需要同步机制

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 7:05:41

Linux怎么按大小筛选文件?

在Linux运维中&#xff0c;按大小筛选文件是高频操作——清理大日志、查找冗余文件、定位磁盘占用大户都离不开它。那么Linux怎么按大小筛选文件?具体请看下文。用find按大小精确查找文件find是最常用、最灵活的方式&#xff0c;支持按字节、KB、MB、GB 等单位筛选&#xff0c…

作者头像 李华
网站建设 2026/5/1 8:04:13

WTAPI框架个人微信机器人开发

WTAPI框架个人微信机器人开发 在微信深度渗透私域流量与客户服务的背景下&#xff0c;WTAPI框架凭借其“全功能覆盖、安全合规、高效扩展”的技术特性&#xff0c;为开发者提供了覆盖多账号管理、智能交互、社群运营等11大核心场景的个人微信机器人开发能力。以下结合WTAPI技术…

作者头像 李华
网站建设 2026/5/1 8:04:23

基于SpringBoot的校园共享电动车短租平台系统(源码+lw+部署文档+讲解等)

背景及意义基于SpringBoot的校园共享电动车短租平台系统&#xff0c;直击师生“校园出行耗时长、电动车私用资源浪费、短租流程繁琐”与学校“调度难、监管弱”的双重痛点&#xff0c;依托SpringBoot的高可靠性与实时数据处理能力&#xff0c;构建“智能借还精准调度安全管控”…

作者头像 李华
网站建设 2026/5/1 7:05:13

股票基础-第17课-行业关键指标与研判

一、行业关键经营指标 1.1 互联网行业 关键指标: 1. 用户增长 月活跃用户(MAU) 日活跃用户(DAU) 用户增长率 2. 流量指标 访问量 页面浏览量(PV) 用户停留时间 3. 变现指标 每用户平均收入(ARPU) 广告收入 付费用户比例 4. 运营指标 获客成本(CAC) 用户留存率 转…

作者头像 李华
网站建设 2026/5/1 5:56:24

后端觉得前端很简单?

话说&#xff1a;程序员的江湖里&#xff0c;有一种神秘的鄙视链。。写 C 的瞧不起写 Java 的&#xff0c;写 Java 的看不上写 PHP 的&#xff0c;而写后端的&#xff0c;总觉得前端不过是写写样式、调调颜色&#xff1b;但真让他们换个岗位&#xff0c;才知道调调颜色这玩意儿…

作者头像 李华
网站建设 2026/5/1 5:19:55

当AI深入车间:从视觉质检到工艺优化的实战图谱

当一颗肉眼难辨的微小瑕疵被AI在毫秒间捕捉&#xff0c;当一段最优化的加工参数组合被算法从百万种可能中寻获&#xff0c;我们看到的不仅是技术的胜利&#xff0c;更是一场关于制造业“经验”与“确定性”的深刻重构。在智能工厂的宏大叙事中&#xff0c;人工智能正从展厅的演…

作者头像 李华