Ashmem 简述(android平台的共享内存机制)

Ashmem 简述_Raurean的博客-CSDN博客

原文的才有文档的,这里仅仅作为记录!

1. 概述
Ashmem(Anonymous Shared Memory,Android 匿名共享内存),它基于 mmap 系统调用,可以让不同进程将同一段物理内存映射到各自的虚拟地址中,从而实现内存共享。

它以驱动程序的形式在内核空间中实现,并通过文件描述符来传递共享内存的句柄。

相对于 Linux 的共享内存, Ashmem 驱动中添加了互斥锁以此实现了同步的机制,并能够辅助内存管理系统来有效地管理不再使用的内存块。

2. 原理
两个进程就像两个平行的世界,A 进程没法直接访问 B 进程的数据,其用户空间的数据存在进程隔离,而内核空间的数据则可以进程间共享。


应用程序不能直接操作设备地址,操作系统通过内存映射(mmap),可以把设备地址映射到进程内核空间的虚拟内存区域。


Android 中,/dev/ashmem是一个虚拟设备,不存在实际文件,只在内核驱动中对应一个inode节点。通过 ashmem 和 binder 相关方法,存在于两个进程中的不同文件描述符,会对应到同一个基于/dev/ashmem创建的临时文件,并将该文件指向的物理内存分别映射到各个进程自己的虚拟内存中,最终实现进程间内存共享。


3. 源码
3.1 源码路径
Framework:
  frameworks/base/core/java/android/os/SharedMemory.java
  frameworks/base/core/java/android/os/MemoryFile.java
  frameworks/base/core/jni/android_os_SharedMemory.cpp
  frameworks/base/core/jni/android_os_MemoryFile.cpp

Native:
  frameworks/native/libs/binder/IMemory.cpp
  frameworks/native/libs/binder/MemoryBase.cpp
  frameworks/native/libs/binder/MemoryHeapBase.cpp
  frameworks/native/libs/binder/MemoryDealer.cpp
  frameworks/native/libs/binder/include/binder/IMemory.h
  frameworks/native/libs/binder/include/binder/MemoryBase.h
  frameworks/native/libs/binder/include/binder/MemoryHeapBase.h
  frameworks/native/libs/binder/include/binder/MemoryDealer.h

System:
  system/core/libcutils/ashmem-host.c   提供给模拟器
  system/core/libcutils/ashmem-dev.c    提供给实际设备
  system/core/include/cutils/ashmem.h

Driver:  
  kernel/msm-5.4/drivers/staging/android/ashmem.c
  kernel/msm-5.4/drivers/staging/android/ashmem.h
  kernel/msm-5.4/drivers/staging/android/uapi/ashmem.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
3.2 驱动层
依托于/dev/ashmem设备,Linux 内核分配并管理 ashmem 的全局内存。

kernel/msm-5.4/drivers/staging/android/ashmem.c
kernel/msm-5.4/drivers/staging/android/ashmem.h

ashmem_area 结构体
/**
 * The lifecycle of this structure is from our parent file's open() until
 * its release(). It is also protected by 'ashmem_mutex'
 * Warning: Mappings do NOT pin this structure; It dies on close()
 */
struct ashmem_area {
  char name[ASHMEM_FULL_NAME_LEN]; // optional name in /proc/pid/maps
  struct list_head unpinned_list;  // list of all ashmem areas
  struct file *file;               // the shmem-based backing file
  size_t size;                     // size of the mapping, in bytes
  unsigned long prot_mask;         // allowed prot bits, as vm_flags
};
1
2
3
4
5
6
7
8
9
10
11
12
ashmem_init()
ashmem 的 init 入口,通过 kmem_cache_create(),创建ashmem_area_cachep和ashmem_range_cachep两个 kmem_cache 对象,此时并没有分配内存;
通过调用misc_register()将其注册为ashmem名称的 misc 设备;
通过调用register_shrinker()向内存管理系统注册内存回收函数。
ashmem_open()
从 ashmem_area_cachep 中分配一块 ashmem_area(asma)共享内存给进程;
对 asma 进行初始化,然后将其记录在 file->private_data 中,进程可以通过返回的 file 指针访问该共享内存。
ashmem_mmap()
Memory Map(内存映射),把 /dev/ashmem 设备文件映射到进程虚拟内存中。

从file->private_data中取出 ashmem_open() 时创建的 asma;
若asma->file为空,则当前为第一次访问该共享空间的进程,需要调用 Linux 提供的 shmem_file_setup() ,在 tmpfs 中创建临时文件用于进程间的内存共享。

ashmem_ioctl()
设置/获取名称;
设置/获取 size 大小;
设置/获取保护位;
锁定/解锁 asma 下的内存块 。
ashmem_pin_unpin()
锁定(pin)或解锁(unpin)内存块。

Ashmem 机制中,正在使用的内存块需要被锁定,不被使用的内存块需要被解除锁定。unpin操作仅改变相关状态标记,并不会改变已经 mmap 的地址空间。因此,用户可以在解锁后重新锁定某块内存块。

Ashmem 机制建立在 Linux 内核的共享内存实现上。同时又向 Linux 内存管理系统的内存回收算法注册接口。系统内存不足时,会依据 LRU 算法回收unpin内存块对应的物理页面。如果不希望内存对象被回收,可以通过修改其状态为pin来保护它。


3.3 系统层
system/core/libcutils/ashmem-dev.c
system/core/include/cutils/ashmem.h

Ashmem 匿名共享内存,需要依赖 System 层和 Driver 层进行交互:

// ashmem.h
// 根据名称和大小,创建 ashmem 区域,返回文件描述符
int ashmem_create_region(const char *name, size_t size);
// 设置 ashmem 访问保护位
int ashmem_set_prot_region(int fd, int prot);
// ashmem 锁定
int ashmem_pin_region(int fd, size_t offset, size_t len);
// ashmem 解锁
int ashmem_unpin_region(int fd, size_t offset, size_t len);
// ashmem 区域的大小
int ashmem_get_size_region(int fd);
1
2
3
4
5
6
7
8
9
10
11
3.4 Native层
frameworks/native/libs/binder/MemoryDealer.cpp

MemoryDealer类可以看做是对 ashmem 的封装,源码位于frameworks/native/libs/binder/目录下。其内部拥有两个重要的成员变量:

mHeap,为MemoryHeapBase类对象,用于描述一块内存;
mAllocator,为SimpleBestFitAllocator类对象,用于分配内存。
MemoryHeapBase继承自抽象类BnMemoryHeap,并使用libcutils库中的 ashmem_create_region和mmap方法进行 ashmem 创建和内存映射。而MemoryBase继承自BnMemory,用于包装MemoryHeapBase对象。

IMemory.h 中,定义了IMemory、IMemoryHeap、BnMemory 和 BnMemoryHeap等匿名共享内存相关的访问接口。几者间的关系如下:


3.5 Framework 层
frameworks/base/core/java/android/os/SharedMemory.java
frameworks/base/core/java/android/os/MemoryFile.java

Java层借助MemoryFile或者SharedMemory创建匿名共享内存。

SharedMemory通过 JNI 调用ashmem_create_region进行匿名共享内存区创建。

MemoryFile对SharedMemory进行了包装,能够标记不再使用的内存区域,方便系统回收。

4. Ashmem 的应用
ashmem 通过共享内存进行数据传递,共享内存的操作需要通过文件句柄 fd。所以,当不同进程间进行内存共享时,需要跨进程传递 fd 信息。因此,在使用 Ashmem 之前,需要在两个进程之前建立 Binder 连接。

通过 Ashmem 传递内容需要进行以下步骤:

创建 Ashmem 区域,并写入待传输数据;
获得该共享内存的 fd 句柄;
打包 fd 到 bundle;
通过 Binder 发送 fd 信息到服务端。
5. ashmem 设备查看
在使用时,进程在 /dev/ashmem/ 目录中创建了一个文件条目,然后删除,但因为它至少有一个打开的文件描述符,所以相应的inode和对应内存区域仍然存在。创建多个具有相同名称的 ashmem 区域,它们都显示为/dev/ashmem/<name> (deleted),但它们中的每一个都对应于不同的inode,因此对应着不同的内存区域。当最后一个文件描述符关闭时,ashmem 临时文件的inode和对应内存会自动回收。


5. 总结


参考链接:

Ashmem机制讲解
Android Ashmem 机制
Ashmem使用方法和原理
Ashmem驱动程序源代码分析
Android 匿名共享内存C++接口分析
Android匿名共享内存(Ashmem)原理
————————————————
版权声明:本文为CSDN博主「Raurean」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/run068/article/details/121695036

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值