最近在优化打印机的打印速度,由于当前的实现存在许多内存拷贝的操作,于是希望借助于android匿名共享内存减少拷贝的次数,达到优化的目的。因为以前并未使用过Ashmem,仅以此篇记录下应用流程。
首先明确一点,共享内存一般应用在跨进程之间,原型如上图,fd为此块共享内存的文件描述符,Client和Server端通过文件描述符fd来操作共享内存
Client端实现步骤:
1.使用ashmem_create_region()接口创建一个长度为length的共享内存,并返回此内存块的文件描述赋
data.fd = ashmem_create_region(NULL,length); if(data.fd < 0) LOGE(TAG,"Creating code cache, ashmem_create_region " "failed with error '%s'", strerror(errno));
2.将此块共享内存以可读可写的方式映射到用户空间,并对此块内存写入数据
data.data = (char *)mmap(NULL, data.length, PROT_READ | PROT_WRITE, MAP_SHARED, data.fd, 0); if(data.data != MAP_FAILED){ LOGE(TAG,"mmap sharemem success...."); memcpy(data.data,gucDotBuffer,length); }else{ LOGE(TAG,"mmap sharemem failed....'%s'",strerror(errno)); }
3.解映射并关闭文件描述符
munmap(data.data,length);close(data.fd);
4.通过binder通信,将共享内存的文件描述符通过Parcel提供的writeFileDescriptor()接口传递到服务端
Parcel data;data.writeFileDescriptor(ash_data.fd,true);
服务端实现流程:
5.首先通过Parcel接口readFileDescriptor()接口取到共享内存块的文件描述符
Parcel data;fd = data.readFileDescriptor();
6.将共享内存块mmap到服务端进程空间,之后就可以操作这块内存了
data.data = (char *)mmap(NULL, data.length, PROT_READ | PROT_WRITE, MAP_SHARED, data.fd, 0);if(data.data != MAP_FAILED){ LOGE(TAG,"mmap sharemem success....");}else{ LOGE(TAG,"mmap sharemem failed....'%s'",strerror(errno));}
7.同理,使用完后需要解映射以及关闭文件描述符,防止内存泄漏
munmap(data.data,data.length);close(data.fd);
注:补充一下,有一点比较有趣的地方是,Client和Server端的文件描述符fd的值打印出来你会发现两者是不一样的,这是因为,每个进程在进程表中都维护着自身的文件描述符表,binder驱动在传递fd的时候,调用了dup()函数对client端的文件描述符拷贝了一份副本给到Server端,两者值不同,但均指向同一个文件。
注2:每调用多一次dup(),返回值就会多加1
注3:需要依赖的头文件
#include#include