news 2026/4/3 2:11:20

【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/3/25 21:07:53

ppInk 终极指南:免费开源屏幕标注工具的完整使用教程

在当今数字化教学、远程协作和在线演示的时代&#xff0c;拥有一款高效便捷的屏幕标注工具至关重要。ppInk 作为 Gink 项目的分支版本&#xff0c;提供了一个功能强大且完全免费的屏幕标注解决方案。这款轻量级工具支持实时标注、多种绘图工具和自定义设置&#xff0c;让您的演…

作者头像 李华
网站建设 2026/3/30 1:54:55

亚马逊日本站办理TELEC认证,还需要办理METI备案吗?

在亚马逊日本站销售带无线功能的产品&#xff08;如蓝牙音箱&#xff09;&#xff0c;仅办 TELEC 认证不够&#xff0c;是否需要 METI 备案取决于产品是否属于日本《电气用品安全法》管控的 PSE 认证范畴&#xff0c;这是平台与日本法规的双重要求。TELEC 认证针对无线射频合规…

作者头像 李华
网站建设 2026/3/26 12:48:41

从Nat Genet到Cell:解析表观在水产研究中的顶刊思路

水产养殖业作为全球粮食安全的重要支柱&#xff0c;正面临着种质资源退化、病害频发及气候变化等多重挑战。与陆生家畜相比&#xff0c;水产动物&#xff08;鱼、虾、贝类&#xff09;展现出更为显著的表型可塑性&#xff1a;即同一基因型个体在不同环境&#xff08;如温度、病…

作者头像 李华
网站建设 2026/3/30 20:14:43

《零基础学 PHP:从入门到实战》·PHP Web 安全开发核心技术与攻防实战演练-XSS 与 CSRF 全面防护

第 4 章:客户端脚本攻防——XSS 与 CSRF 全面防护 章节介绍 学习目标 通过本章学习,您将能够: 理解反射型、存储型和 DOM 型 XSS 攻击的原理、区别及危害掌握 CSRF(跨站请求伪造)的攻击流程与防御机制学会在 PHP 中正确使用输出转义函数防止 XSS 攻击实现完整的 CSRF Token…

作者头像 李华
网站建设 2026/4/1 21:37:30

计算广告:智能时代的营销科学与实践(十一)

目录 6.3 广告交易平台 一、核心定位&#xff1a;市场中立的“交易所” 二、核心产品功能与机制 1. 市场接入与标准化&#xff08;创造流动性&#xff09; 2. 实时竞价引擎&#xff08;执行交易&#xff09; 3. 交易类型与市场分层&#xff08;满足多样性&#xff09; 4.…

作者头像 李华
网站建设 2026/3/31 8:37:50

5、深入了解Bash变量:从基础到高级应用

深入了解Bash变量:从基础到高级应用 1. 变量基础 在Bash脚本编程中,变量是存储数据的基本单元。与将命令结果写入文件相比,变量存储在内存中,检查速度更快,并且Bash对变量大小没有上限。 1.1 变量声明 使用 declare 命令声明变量。例如,声明一个名为 COST 的变量…

作者头像 李华