Android 匿名共享内存 Ashmem(c 库接口)
Ashmem
Android 系统的匿名共享内存 Ashmem 驱动程序利用了 Linux 的共享内存子系统导出的接口来实现.
在 Android 系统中, 匿名共享内存也是进程间通信方式的一种.
相比于 malloc 和 anonymous/named mmap 等传统的内存分配机制, Ashmem 的优势是通过内核驱动提供了辅助内核的内存回收算法机制 (pin/unpin).
内存回收算法机制就是当你使用 Ashmem 分配了一块内存, 但是其中某些部分却不会被使用时, 那么就可以将这块内存 unpin 掉.
unpin 后, 内核可以将它对应的物理页面回收, 以作他用. 你也不用担心进程无法对 unpin 掉的内存进行再次访问, 因为回收后的内存还可以再次被获得 (通过缺页 handler), 因为 unpin 操作并不会改变已经 mmap 的地址空间.
Android 匿名共享内存接口
源码是最好的老师, 废话不多说, 直接看代码.
源码路径: system/core/libcutils/ashmem-dev.c
Android 源码中, ashmem 的实现:
打开共享内存:/*
* ashmem_create_region - creates a new ashmem region and returns the file
* descriptor, or <0 on error
*
* `name' is an optional label to give the region (visible in /proc/pid/maps)
* `size' is the size of the region, in page-aligned bytes
*/
intashmem_create_region(constchar*name,size_tsize)
{
intret,save_errno;
intfd=__ashmem_open();
if(fd<0){
returnfd;
}
if(name){
charbuf[ASHMEM_NAME_LEN]={0};
strlcpy(buf,name,sizeof(buf));
ret=TEMP_FAILURE_RETRY(ioctl(fd,ASHMEM_SET_NAME,buf));
if(ret<0){
gotoerror;
}
}
ret=TEMP_FAILURE_RETRY(ioctl(fd,ASHMEM_SET_SIZE,size));
if(ret<0){
gotoerror;
}
returnfd;
error:
save_errno=errno;
close(fd);
errno=save_errno;
returnret;
}
在函数中调用驱动接口:
__ashmem_open
__ashmem_open 函数的实现如下:/* logistics of getting file descriptor for ashmem */
staticint__ashmem_open_locked()
{
intret;
structstat st;
intfd=TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE,O_RDWR));
if(fd<0){
returnfd;
}
ret=TEMP_FAILURE_RETRY(fstat(fd,&st));
if(ret<0){
intsave_errno=errno;
close(fd);
errno=save_errno;
returnret;
}
if(!S_ISCHR(st.st_mode)||!st.st_rdev){
close(fd);
errno=ENOTTY;
return-1;
}
__ashmem_rdev=st.st_rdev;
returnfd;
}
staticint__ashmem_open()
{
intfd;
pthread_mutex_lock(&__ashmem_lock);
fd=__ashmem_open_locked();
pthread_mutex_unlock(&__ashmem_lock);
returnfd;
}
可见函数最后是通过 open 去操作 ashmem 驱动文件.
返回为一个文件描述符.intashmem_valid(intfd)
{
return__ashmem_is_ashmem(fd,0)>=0;
}
除此之外, 源码中还提供了几个接口函数:
1. 锁定匿名共享内存块intashmem_pin_region(intfd,size_toffset,size_tlen)
{
structashmem_pin pin={offset,len};
intret=__ashmem_is_ashmem(fd,1);
if(ret<0){
returnret;
}
returnTEMP_FAILURE_RETRY(ioctl(fd,ASHMEM_PIN,&pin));
}
2. 解锁匿名共享内存块intashmem_unpin_region(intfd,size_toffset,size_tlen)
{
structashmem_pin pin={offset,len};
intret=__ashmem_is_ashmem(fd,1);
if(ret<0){
returnret;
}
returnTEMP_FAILURE_RETRY(ioctl(fd,ASHMEM_UNPIN,&pin));
}
3. 获取大小intashmem_get_size_region(intfd)
{
intret=__ashmem_is_ashmem(fd,1);
if(ret<0){
returnret;
}
returnTEMP_FAILURE_RETRY(ioctl(fd,ASHMEM_GET_SIZE,NULL));
}
因为是文件描述符, 所以关闭直接采用 close.
close(fd)
使用例子
创建共享内存fd=ashmem_create_region(NULL,length);
if(fd<0)
printf("Creating code cache, ashmem_create_region error.");
将共享内存映射到用户空间data=(char*)mmap(NULL,data.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(data!=MAP_FAILED){
printf("mmap sharemem success....");
memcpy(data.data,gucDotBuffer,length);
}else{
printf("mmap sharemem failed....'%s'",strerror(errno));
}
关闭映射并关闭共享内存文件munmap(data,length);
close(fd);
来源: http://www.jianshu.com/p/41c4b1bf4873