当前位置: 首页 > Linux

Android共享内存

时间:2023-04-06 20:49:20 Linux

最近遇到什么问题,整理一下文档。系统写一个题目要花很多时间,我还是抽不出时间。这个问题的起因是有人问共享内存,说Binder是基于共享内存实现的,之前在网上看到过。我不知道这种说法的出处是什么,但这是完全错误的。很多人都这么说,我也有点懵。最好看看Ashmem的实现。共享内存的本质是让多个进程访问同一个内存空间。我们知道每个进程都有独立的地址空间,不能互相访问。但是,进程实际分配的内存来自于物理内存。进程可以访问内核空间中所有可分配的物理内存,因此多个进程可能使用同一块物理内存。最简单的方法是使用内存文件共享。在内存中创建一个内存文件,然后通过mmap()映射到进程空间,因为每个进程都映射同一个内存文件,本质上使用的是同一个内存。Linux系统中有很多共享内存机制,但是大部分和上面的简单方法本质上是一样的,都是访问同一个内存文件。常用的内存共享机制包括SystemV共享内存。POSIX共享内存。通过memfd_create()创建共享文件。SystemV共享内存SystemV共享内存使用的接口包括:shmget()、shmat()、shmdt()、shmctl()等,shmget()用于打开或创建一块共享内存区域,其定义为如下。intshmget(key_tkey,size_tsize,intshmflg);其中key为标识共享内存的key值,size为要建立的共享内存的大小,shmflg为IPC_CREAT、IPC_EXCL等。当key为IPC_PRIVATE时,将创建新的共享内存。key不是IPC_PRIVATE,key对应的共享内存不存在。如果shmflg是IPC_CREAT或IPC_CREAT|IPC_EXCL,将创建一个新的共享内存。如果key对应的共享内存存在,shmflg为IPC_CREAT打开共享内存,shmflg为IPC_CREAT|IPC_EXC并返回错误。shmget()创建的共享内存在tmpfs文件系统中,多个进程可以使用同一个key共享内存。一个常见的做法是使用ftok()来获取文件的key,这样进程就可以打开同一个文件。SystemV的共享内存可以通过“/proc/sysvipc/shm”查看。POSIX共享内存POSIX共享内存使用的接口包括shm_open()、shm_unlink()、mmap()等,对这块共享内存的操作更像是操作普通文件。该过程使用shm_open()打开或创建文件,使用ftruncate()调整文件大小(创建新文件时),然后使用mmap()映射完成共享。shm_open()的定义如下。intshm_open(constchar*name,intoflag,mode_t模式);shm_open()的定义与open()类似,可以使用oflag来指定创建或打开文件的属性。使用shm_open()创建共享内存文件时,如果name只是一个名称而不是完整路径,则会在“/dev/shm/”下创建一个文件,而/dev/shm也是建立在tmpfs上的文件系统。由memfd_create()创建memfd_create()创建一个匿名文件并返回文件描述符。这个文件和普通文件一样,可以进行修改、截取、映射等操作。不同的是,这个文件存储在RAM中,并在tmpfs文件系统中创建。在共享内存中使用时,有一个问题如何让另一个进程获取这个文件?因为memfd_create()创建的是一个匿名文件,所以在文件系统中找不到fd,导致文件共享困难。不可能像其他共享内存机制一样就共享的文件名达成一致。一个可行的方案是通过proc传输文件。进程创建的匿名文件记录在proc系统中,存在于“/proc//fd/”中。创建文件的进程需要将这个路径传递给需要共享的进程,打开路径实现文件共享。AshmemAshmem特性Android没有使用Linux上现有的共享内存机制,而是编写了一个新的机制Ashmem。与上述机制不同的是,Ashmem是通过系统调用实现的,而是表现为一个字符设备,通过操作字符设备获取共享内存的描述符。Ashmem基于Linux虚拟内存系统shmem,共享内存最终表现为tmpfs文件系统中的一个匿名文件。Ashmem添加了内存管理(pin、unpin、purge)和内存恢复(shrink)机制,从而降低了用户的复杂性。Ashmem与AndroidMemoryFile紧密相连,上层应用使用MemoryFile类完成内存共享。MemoryFile通过Binder传递Ashmem共享内存的描述符,描述符的转换在Binder驱动中完成。盗图,细节就不分析了。https://my.oschina.net/youran...Binder和AshmemBinder与共享内存有什么关系?我认为这并不重要。在Android系统中,如果要在多个进程中共享Ashmem,需要将共享内存的FD传递给其他进程。这个过程是用Binder实现的。另外,在使用共享内存时,不可避免地要在进程之间传递控制信息。这种传输只能通过Android中的Binder完成。此外,Binder似乎与Ashmem没有任何关系。Binder在传递FD的过程中将FD从一个进程转换到另一个进程。这段代码值得一看。staticvoidbinder_transaction(structbinder_proc*proc,structbinder_thread*thread,structbinder_transaction_data*tr,intreply){......caseBINDER_TYPE_FD:{inttarget_fd;结构文件*文件;......//获取内核文件中文件的描述=fget(fp->handle);…//获取目标进程中未使用的FDtarget_fd=task_get_unused_fd_flags(target_proc,O_CLOEXEC);…//将文件与目标进程新获取的FD对应起来task_fd_install(target_proc,target_fd,file);...fp->活页夹=0;fp->handle=target_fd;}休息;…fd转换在内核实现起来很方便,但是在用户空间就很麻烦了。用户空间可以通过“/proc//fd/”下的文件访问同一个匿名文件,这在memfd_create中有描述。Ashmem是一种共享内存机制,也可以认为是IPC的一种方式。它与Binder不冲突,应根据不同的场合以不同的方式使用。Binder用于传输信息和小数据。Ashmem用于共享大数据。小于1M的数据,如果不经常使用,可以使用Binder传输。因为即使使用Ashmem也无法避免Binder,所以最好将数据一起发送。Ashmem更喜欢共享纯数据。如果把控制信息也放到共享内存中,会增加数据维护的复杂度,得不偿失。