news 2026/6/23 19:27:08

【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/6/20 15:31:59

如何实现xtreme1与Apollo相机外参的双向转换

如何实现xtreme1与Apollo相机外参的双向转换一、概述二、什么是相机外参&#xff1f;三、两种格式的主要区别1、xtreme1格式2、Apollo格式3、关键差异四、转换原理1. 核心数学概念1.1、变换矩阵1.2、四元数2. 转换流程五、完整实现六、代码输出一、概述 在自动驾驶和计算机视觉…

作者头像 李华
网站建设 2026/6/18 14:32:02

常见CE认证电子电器产品有哪些?

常见需办理 CE 认证的电子电器产品覆盖消费电子、家用电器、工业电气、无线通信设备等多个品类&#xff0c;核心需符合低电压指令&#xff08;LVD&#xff09; 与电磁兼容指令&#xff08;EMC&#xff09; &#xff0c;无线类产品额外需满足无线电设备指令&#xff08;RED&…

作者头像 李华
网站建设 2026/6/18 18:39:26

LLM 安全攻防战!最新对齐技术藏不住了

大语言模型&#xff08;LLM&#xff09;正从 “能力突破” 迈向 “效率革命”&#xff0c;近期顶会研究集中爆发关键进展。推理优化成核心战场&#xff1a;PagedAttention 通过内存分页管理破解 KV 缓存碎片难题&#xff0c;Raddix 树结构实现跨请求缓存复用&#xff1b;推测解…

作者头像 李华