Ashmem(Android共享内存)使用方法和原理

如下内容基于Android API Version 27(Android 8.1)Linux Kernel 3.18.0java

简介

Ashmem即Android Shared Memory, 是Android提供的一种内存共享的机制。node

使用

Application Java层借助MemoryFileSharedMemory,Native层借助libc的ashmem_create_regionmmap系统调用进行使用。linux

MemoryFile和SharedMemory底层也是基于ashmem_create_region/mmapandroid

MemoryFile

MemoryFile是对SharedMemory的包装,官方推荐使用SharedMemory。c#

Applications should generally prefer to use {@link SharedMemory} which offers more flexible access & control over the shared memory region than MemoryFile does.数组

SharedMemory

SharedMemory只能经过调用SharedMemory.create静态方法或者经过Parcel反序列化的方式进行建立。安全

SharedMemory的建立者进程经过静态方法建立,使用者进程经过Parcel反序列化来建立。函数

由于SharedMemory类实现了Parcelable,因此能够经过binder跨进程传输。flex

ashmem_create_region 和 mmap

int ashmem_create_region(const char *name, size_t size) 复制代码

用于建立共享内存,函数内部首先经过open函数打开/dev/ashmem设备,获得文件描述符后,经过调用ioctl设置fd的名称和大小。spa

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
复制代码

经过binder将fd传递到其余进程后,其余进程能够经过mmap系统调用,将共享内存映射到当前进程的地址空间,以后就能够经过返回的内存首地址进行内存读写。

这样,两个进程之间就实现了直接的内存共享,得到了极高的进程间通讯效率。

Ashmem的Pin和Unpin

ashmem驱动提供了两个用于内存管理的ioctl操做命令:pin/unpin,直接经过ashmem_create_region建立的共享内存默认是pined的状态,也就是说,应用程序不主动关闭共享内存fd的状况下,这篇内存会始终保留,直到进程死亡。

若是调用unpin将共享内存中的某段内存解除锁定,以后若是系统内存不足,会自动释放这部份内存,再次使用同一段内存前应该先执行pin操做,若是pin操做返回ASHMEM_WAS_PURGED,也就是说内存已经被回收,已经回收的内存再次访问会触发缺页中断从新进行物理内存的分配,所以这段内存里的数据已经不是起初的那个数据了,若是仍旧当作原始数据进行访问必然引起错误。

经过pin/unpin命令,配合ashmem驱动,能够进行简单的内存管理。

原理

Ashmem的核心原理主要是两部分:驱动和fd传递。

驱动

Ashmem是Linux内核中的一个misc设备,对应的设备文件是/dev/ashmem,此设备是一个虚拟设备,不存在实际文件,只在内核驱动中对应一个inode节点。Ashmem在驱动层是基于linux系统的共享内存功能实现的,Ashmem能够理解为只是对原生的共享内存进行了一层包装,使其更方便在Android系统上使用。

ashmem设备文件支持以下操做:

// /drivers/staging/android/ashmem.c
809static const struct file_operations ashmem_fops = {
810	.owner = THIS_MODULE,
811	.open = ashmem_open,
812	.release = ashmem_release,
813	.read = ashmem_read,
814	.llseek = ashmem_llseek,
815	.mmap = ashmem_mmap,
816	.unlocked_ioctl = ashmem_ioctl,
817#ifdef CONFIG_COMPAT
818	.compat_ioctl = compat_ashmem_ioctl,
819#endif
820};
复制代码

ashmem建立:(从Java层到驱动层的调用链)

[java] android.os.SharedMemory#create
[jni] /frameworks/base/core/jni/android_os_SharedMemory.cpp#SharedMemory_create
[libc] /system/core/libcutils/ashmem-dev.c#ashmem_create_region
[driver] /drivers/staging/android/ashmem.c#ashmem_open
复制代码
ashmem_open

ashmem_open中只是建立了一个标识ashmem的结构体,而后返回fd,并无进行实际的内存分配(不管是虚拟内存仍是物理内存)。 获得文件描述符后,就可使用ashmem_mmap将内核中的共享内存区域映射到进程的虚拟地址空间。

ashmem_mmap

ashmem_mmap经过调用内核中shmem相关函数在tempfs建立了一个大小等于建立ashmem时传入大小的临时文件(因为是内存文件,因此磁盘上不存在实际的文件),而后将文件对应的内存映射到调用mmap的进程。(注意map的是临时文件而不是ashmem文件)

其中涉及到的shmem函数包括shmem_file_setupshmem_set_file,他们为该临时文件建立inode节点,将文件关联到为该文件配的虚拟内存,同时为该文件设置文件本身的文件操做指针(Linux原始共享内存shmem的文件操做),并为虚拟内存设置缺页处理函数。这样后续对共享内存的操做就变为了对tempfs文件节点的操做。当首次访问共享内存时触发缺页中断处理函数并为该虚拟内存分配实际的物理内存。

tempfs是Unix-like系统中一种基于内存的文件系统,具备极高的访问效率。
shmem是Linux自带的进程间通讯机制:共享内存Shared Memory
共享内存的虚拟文件记录在/proc/<pid>/maps文件中,pid表示打开这个共享内存文件的进程ID。

ashmem_pin/ashmem_unpin

pinunpinashmemiotrl支持的两个操做,用于共享内存的分块使用和分块回收,用于节省实际的物理内存。 新建立的共享内存默认都是pined的,当调用unpin时,驱动将unpined的内存区域所在的页挂在一个unpinned_list链表上,后续内存回收就是基于unpinned_list链表进行。

ashmem驱动初始化函数ashmem_init里调用了内核函数register_shrinker,注册了一个内存回收回调函数ashmem_shrink,当系统内存紧张时,就会回调ashmem_shrink,由驱动自身进行适当的内存回收。驱动就是在ashmem_shrink中遍历unpinned_list进行内存回收,以释放物理内存。

ashmem fd的传递:

fd经过Binder传递。

Binder机制不只支持binder对象的传递,还支持文件描述符的传递。fd通过binder驱动时,binder驱动会将源进程的fd转换成目标进程的fd,转换过程为:取出发送方binder数据里的fd,经过fd找到文件对象,而后为目标进程建立fd,将目标进程fd和文件对象进行关联,将发送方binder数据里的fd改成目标进程的fd,而后将数据发送给目标进程。这个过程至关于文件在目标进程又打开了一次,目标进程使用的是本身的fd,但和源进程都指向的是同一个文件。这样源进程和目标进程就均可以map到同一片内存了。

使用场景

  • 进程间共享较大的数据,好比大致积的bitmap和较大的数据数组。
  • 向内核偷内存。因为ashmem内存既不在java heap上也不在native heap上,对ashmem的使用可使进程得到更多的额外内存,若是过分使用会有物理内存耗尽的风险。
  • 借助Bitmap解码的inPurgeable属性,在android4.x及如下系统版本中实现内存在ashmem中分配,以节省Java堆内存。好比fresco图片加载库针对Android4.x及如下的机型对inPurgeable属性的使用。

总结

Ashmem经过对Linux共享内存的扩展,一方面使其使用更简单,另外一方面使其只能经过binder传递,增长了安全性。Ashmem在Android系统中起着很是重要的做用,好比整个显示系统Activity-WindowsManagerService-SurfaceFlinger就是经过Ashmem传递的帧数据-Surface。

参考:
blog.csdn.net/Luoshengyan…
blog.csdn.net/Luoshengyan…
blog.csdn.net/Luoshengyan…
www.jianshu.com/p/d9bc9c668…

相关文章
相关标签/搜索