news 2025/12/25 12:00:30

【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进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/12 15:44:06

股票基础-第15课-行业分析框架与分类

一、行业分析的重要性 1.1 为什么选对行业很关键? 核心观点: 选对行业赛道,比选对公司更重要。 原因: 1. 行业趋势决定公司上限 好行业更容易出好公司 差行业很难出好公司 例如:科技行业 vs 传统制造业 2. 行业周期影响所有公司 行业上升期,大部分公司都受益 行业下降…

作者头像 李华
网站建设 2025/12/12 15:43:47

显卡驱动清理工具深度解析:DDU完整使用教程

显卡驱动清理工具深度解析&#xff1a;DDU完整使用教程 【免费下载链接】display-drivers-uninstaller Display Driver Uninstaller (DDU) a driver removal utility / cleaner utility 项目地址: https://gitcode.com/gh_mirrors/di/display-drivers-uninstaller 显卡驱…

作者头像 李华
网站建设 2025/12/12 15:43:42

Figma中文界面完整解决方案:设计师的本地化工作流优化指南

Figma中文界面完整解决方案&#xff1a;设计师的本地化工作流优化指南 【免费下载链接】figmaCN 中文 Figma 插件&#xff0c;设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 还在为Figma英文界面带来的操作障碍而困扰吗&#xff1f;专业的设…

作者头像 李华
网站建设 2025/12/12 15:43:28

ENVI Classic遥感影像处理终极指南:从入门到精通快速上手

ENVI Classic遥感影像处理终极指南&#xff1a;从入门到精通快速上手 【免费下载链接】ENVIClassic使用手册下载 ENVI Classic 使用手册下载 项目地址: https://gitcode.com/Open-source-documentation-tutorial/62ddd 还在为复杂的遥感影像处理而烦恼吗&#xff1f;想要…

作者头像 李华