unix 共享内存 存储映射 注意与android中ashm的区别与联系
android ashm
http://blog.csdn.net/luoshengyang/article/details/6651971
用了aidl,服务实现后在server(bindService)组件的onCreate中注册到servicemanager: ServiceManager.addService("AnonymousSharedMemory", memoryService);注意,这个应用的Android.mk中有:LOCAL_CERTIFICATE := platform,所以能注册上。
luo说:匿名共享内存一般是结合Binder来使用,没有Binder,匿名共享内存也一样可以使用,只要你有办法将匿名共享内存的文件描述符从一个进程传到另外一个进程就可以了。就像使用unix共享内存一样。
http://blog.csdn.net/luoshengyang/article/details/6664554
http://blog.csdn.net/luoshengyang/article/details/6666491
1. MemoryFile.java::native_open -> cpp -> ashmem_create_region -> /dev/ashmem -> Ashmem驱动程序中创建了一个ashmem_area结构: struct ashmem_area, ashmem_area结构保存在打开文件结构体(file *)的private_data域.
2. MemoryFile.java::native_mmap -> cpp -> mmap(...,/dev/ashmem...) -> ashmem_mmap -> shmem_file_setup:
调用了Linux内核提供的shmem_file_setup函数来在临时文件系统tmpfs中创建一个临时文件,这个临时文件与Ashmem驱动程序创建的匿名共享内存对应。函数shmem_file_setup是Linux内核中用来创建共享内存文件的方法,而Linux内核中的共享内存机制其实是一种进程间通信(IPC)机制,它的实现相对也是比较复杂,Android系统的匿名共享内存机制正是由于直接使用了Linux内核共享内存机制,它才会很小巧,它站在巨人的肩膀上了。关于Linux内核中的共享内存的相关知识,可以参考前面Android学习启动篇一文中提到的一本参考书籍《Linux内核源代码情景分析》的第六章传统的Unix进程间通信第七小节共享内存。
通过shmem_file_setup函数创建的临时文件vmfile最终就保存在vma->file中了。这里的vma是由Linux内核的文件系统层传进来的,它的类型为struct vm_area_struct,它表示的是当前进程空间中一块连续的虚拟地址空间,它的起始地址可以由用户来指定,也可以由内核自己来分配,这里我们从JNI方法native_mmap调用的mmap的第一个参数为NULL可以看出,这块连续的虚拟地址空间的起始地址是由内核来指定的。文件内存映射操作完成后,用户访问这个范围的地址空间就相当于是访问对应的文件的内容了。有关Linux文件的内存映射操作,同样可以参考前面Android学习启动篇一文中提到的一本参考书籍《Linux内核源代码情景分析》的第二章内存管理第十三小节系统调用mmap。从这里我们也可以看出,Android系统的匿名共享内存是在虚拟地址空间连续的,但是在物理地址空间就不一定是连续的了。
同时,这个临时文件vmfile也会保存asma->file域中,这样,Ashmem驱动程序后面就可以通过在asma->file来操作这个匿名内存共享文件了。
函数ashmem_mmap执行完成后,经过层层返回到JNI方法native_mmap中去,就从mmap函数的返回值中得到了这块虚拟空间的起始地址了,这个起始地址最终返回到应用程序框架层的MemoryFile类的构造函数中,并且保存在成员变量mAddress中,后面,共享内存的读写操作就是对这个地址空间进行操作了。
2. MemoryFile.java::native_read/write...
小结:ashmem与Unix的内存共享机制相似,都是在某个相对的虚拟文件系统中创建一个文件,然后将这个文件映射到用户进程空间中,从而对进程空间中的那块区域的读写以对底层文件的读写。
二者的区别是:
1. 它们的API不同:ashmem底层是一个驱动程序文件(/dev/ashmem),调用的系统调用是mmap(对应驱动中的相应函数ashmem_mmap,ashmem_mmap再去调用shmem_file_setup函数创建了临时文件vmfile。。。),Unix共享内存的api是shmget和shmat(attach即将内核相应的结构或文件映射用户进程空间)。
2. ashmem底层是一个驱动程序,而Unix中的暂不清楚如何实现。
另外:ashmem与mmap的区别:一个是驱动文件,一个是系统调用。mmap就是将一个文件映射到用户进程空间的一块区域,所以它本身就是ashmem机制的一部份,但不是全部。
(end)
Unix/Linux下的IPC---共享内存 (来自:http://bdxnote.blog.163.com/blog/static/844423520100105258311/)
2010-01-10 17:25:08| 分类: C/VC/C++ |字号 订阅
共享内存指的是:把所有需要使用的共享数据都存放在共享内存(IPC shared memory region)区域中,任何想要访问这些共享数据的进程都必须在自己的进程地址空间中新增加一块内存区域,用来映射存放共享数据的物理内存页面;也就是说,任何想要访问这些共享数据的进程都必须把存放共享数据的物理内存页面的全部地址空间都映射到自己的进程地址空间中;这就是System V共享内存的实现机制;
系统调用mmap()通过映射一个普通文件来实现共享内存;而System V则是通过映射特殊文件系统shm中的一个文件来实现进程间共享内存通信的;也就是说,每个共享内存区域都对应特殊文件系统shm中的一个文件(通过struct shmid_kernel结构来关联起来的);
一、System V共享内存的原理:
进程间需要共享的数据存放在一个叫做IPC共享内存区域的地方,所有需要访问这些共享数据的进程都要把存放这些共享数据的共享内存区域以及所对应的物理内存页面的全部地址空间都映射到自己的进程地址空间中.System V共享内存通过系统调用shmget()来获得或创建一个IPC共享内存区域,并返回这个共享内存区域的唯一标识符.内核在保证系统调用shmget()获得或创建一个共享内存区域,并初始化该共享内存区域对应的shmid_kernel结构的同时,还将在特殊文件系统shm中创建或打开一个同名的文件,并在内存中建立起该文件的struct dentry和struct inode结构,新建的文件不属于任何一个进程(任何进程够可以访问该共享内存区域).所有这一切操作都是系统调用shmget()完成的;
注意:每一个共享内存区域都有一个控制结构:struct shmid_kernel,shmid_kernel结构是共享内存区域中非常重要的一个结构,它是把存储管理与文件系统结合起来的桥梁;struct shmid_kernel结构的定义如下:
struct shmid_kernel
{
struct kern_ipc_perm shm_perm;
struct file* shm_file;
int id;
unsigned long shm_nattch;
unsigned long shm_segsz;
time_t shm_atim;
time_t shm_dtim;
time_t shm_ctim;
pid_t shm_cprid;
pid_t shm_lprid;
};
该结构中最重要的一个字段就是shm_file,它存储了将被映射文件的地址,每个共享内存区域对象都对应特殊文件系统shm中的一个文件.一般情况下,特殊文件系统shm中的文件是不能使用read()、write()函数进行访问的,当采用共享内存机制把其中的文件映射到进程的地址空间中之后,可以直接采用访问内存的方式对其进行访问;
与System V共享内存相关的数据结构,如图:
正如消息队列和信号量集一样,系统内核通过数据结构struct ipc_ids shm_ids来维护系统中所有的共享内存区域对象.上图中的shm_ids.entries变量指向一个ipc_id结构数组,而每个ipc_id数组结构中都有一个指向kern_ipc_perm结构的指针,对于System V来说,kern_ipc_perm结构的宿主就是struct shmid_kernel结构,而shmid_kernel结构是用来描述一个共享内存区域对象的,这样内核就能控制到系统中的所有共享内存区域对象.同时,在shmid_kernal结构中的struct file类型的指针指向特殊文件系统shm中相应的文件,这样,一个共享内存区域对象就与特殊文件系统shm中的一个文件关联起来了;
二、映射文件地址空间到进程地址空间:
在创建或打开一个共享内存区域对象之后,还要把它映射到进程的地址空间中,系统调用shmat()用来完成这项任务;由于在调用shmget()时就已经在特殊文件系统shm中创建了一个同名文件与该共享内存区域对象对应,因此,调用shmat()的过程相当于把特殊文件系统shm中的同名文件映射到进程地址空间的过程,原理与mmap()大同小异;
三、System V共享内存的系统API:
System V共享内存主要有以下几个API:shmget()、shmat()、shmdt()和shmctl();
#include <sys/ipc.h>
#include <sys/shm.h>
shmget()用来获得或创建共享内存对象并返回该共享内存对象的ID的,如果指定的共享内存不存在,就创建相应的共享内存区域.
shmat()用来把共享内存区域的地址空间映射到进程地址空间中,这样,进程就能方便地对共享内存区域进程访问了.
shmdt()用来解除共享内存区域对象与进程地址空间的映射关系,也就是解除进程对共享内存区域的映射.
shmctl()实现对共享内存区域的控制操作.
注意:shmget()的内部实现包含了许多System V共享内存机制;shmat()在把共享内存区域映射到进程地址空间时,并不真正改变进程的页表.当进程第一次访问共享内存映射区域时,会因为没有物理页表的分配而导致一个缺页异常,然后内核再根据相应的存储管理机制为共享内存映射区域分配相应的物理页表;
四、System V共享内存限制:
在/proc/sys/kernel/目录下记录着System V共享内存机制的一些限制;比如:一个共享内存区域的最大字节数shmmax,系统范围内最大共享内存区标识符数shmmni,等等;可以手工对其进行调整,但是不推荐这样做;
五、System V共享内存机制与内存映射机制的区别:
1、System V共享内存中的数据从来不会写入到实际磁盘文件中去;而通过系统调用mmap()映射普通文件实现的共享内存通信机制可以指定何时把共享内存中的数据写入到实际的磁盘文件中;注:System V是通过映射特殊文件系统shm中的文件来实现的,特殊文件系统shm的安装点是在系统的交换分区上,系统内核重新启动并引导之后,所有的内容全部丢失;
2、System V共享内存区域对象是随内核持续的,即使所有访问共享内存区域对象的进程都已经正常结束,共享内存区域对象仍然在内核中存在(除非显式删除共享内存区域对象),在内核重新引导之前,对该共享内存区域对象的任何改写操作都将一直保留;简单地说,共享内存区域对象的生命周期跟系统内核的生命周期是一致的,而且共享内存区域对象的作用域范围就是在整个系统内核的生命周期之内;
3、通过调用mmap()映射普通文件进行进程间通信时,一定要注意考虑"进程何时终止"对通信的影响.而通过System V共享内存实现的进程间通信则不然.
六、结论:
共享内存允许两个或多个进程共享同一个给定的存储区,因为不需要来回地复制数据,所以,它是最快的一种进程间通信机制;共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿名映射)的机制实现,也可以通过System V的共享内存机制实现.应用接口和原理很简单,内部机制复杂.为了实现更安全的通信,往往还与信号灯等同步机制共同使用;
共享内存涉及到存储管理和文件系统等方面的知识,深入理解其内部机制有一定的难度,关键还是要紧紧抓住内核使用的重要数据结构.System V共享内存是以文件的形式组织在特殊文件系统shm中的.通过shmget()可以创建或获得共享内存标识符.取得共享内存标识符后,要通过shmat()把这个共享内存区域映射到本进程的地址空间中;