Ashmem
Android系統(tǒng)的匿名共享內(nèi)存Ashmem驅(qū)動(dòng)程序利用了Linux的共享內(nèi)存子系統(tǒng)導(dǎo)出的接口來實(shí)現(xiàn)输玷。
在Android系統(tǒng)中蹋嵌,匿名共享內(nèi)存也是進(jìn)程間通信方式的一種。
相比于malloc和anonymous/named mmap等傳統(tǒng)的內(nèi)存分配機(jī)制耍攘,Ashmem的優(yōu)勢是通過內(nèi)核驅(qū)動(dòng)提供了輔助內(nèi)核的內(nèi)存回收算法機(jī)制(pin/unpin)。
內(nèi)存回收算法機(jī)制就是當(dāng)你使用Ashmem分配了一塊內(nèi)存,但是其中某些部分卻不會被使用時(shí)藏杖,那么就可以將這塊內(nèi)存unpin掉。
unpin后脉顿,內(nèi)核可以將它對應(yīng)的物理頁面回收蝌麸,以作他用。你也不用擔(dān)心進(jìn)程無法對unpin掉的內(nèi)存進(jìn)行再次訪問艾疟,因?yàn)榛厥蘸蟮膬?nèi)存還可以再次被獲得(通過缺頁handler)来吩,因?yàn)閡npin操作并不會改變已經(jīng) mmap的地址空間。
android匿名共享內(nèi)存接口
源碼是最好的老師蔽莱,廢話不多說弟疆,直接看代碼。
源碼路徑:system/core/libcutils/ashmem-dev.c
android源碼中盗冷,ashmem的實(shí)現(xiàn):
打開共享內(nèi)存:
/*
* 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
*/
int ashmem_create_region(const char *name, size_t size)
{
int ret, save_errno;
int fd = __ashmem_open();
if (fd < 0) {
return fd;
}
if (name) {
char buf[ASHMEM_NAME_LEN] = {0};
strlcpy(buf, name, sizeof(buf));
ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_NAME, buf));
if (ret < 0) {
goto error;
}
}
ret = TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_SIZE, size));
if (ret < 0) {
goto error;
}
return fd;
error:
save_errno = errno;
close(fd);
errno = save_errno;
return ret;
}
在函數(shù)中調(diào)用驅(qū)動(dòng)接口:
__ashmem_open
__ashmem_open函數(shù)的實(shí)現(xiàn)如下:
/* logistics of getting file descriptor for ashmem */
static int __ashmem_open_locked()
{
int ret;
struct stat st;
int fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR));
if (fd < 0) {
return fd;
}
ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
if (ret < 0) {
int save_errno = errno;
close(fd);
errno = save_errno;
return ret;
}
if (!S_ISCHR(st.st_mode) || !st.st_rdev) {
close(fd);
errno = ENOTTY;
return -1;
}
__ashmem_rdev = st.st_rdev;
return fd;
}
static int __ashmem_open()
{
int fd;
pthread_mutex_lock(&__ashmem_lock);
fd = __ashmem_open_locked();
pthread_mutex_unlock(&__ashmem_lock);
return fd;
}
可見函數(shù)最后是通過open去操作ashmem驅(qū)動(dòng)文件怠苔。
返回為一個(gè)文件描述符。
int ashmem_valid(int fd)
{
return __ashmem_is_ashmem(fd, 0) >= 0;
}
除此之外仪糖,源碼中還提供了幾個(gè)接口函數(shù):
1. 鎖定匿名共享內(nèi)存塊
int ashmem_pin_region(int fd, size_t offset, size_t len)
{
struct ashmem_pin pin = { offset, len };
int ret = __ashmem_is_ashmem(fd, 1);
if (ret < 0) {
return ret;
}
return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_PIN, &pin));
}
2. 解鎖匿名共享內(nèi)存塊
int ashmem_unpin_region(int fd, size_t offset, size_t len)
{
struct ashmem_pin pin = { offset, len };
int ret = __ashmem_is_ashmem(fd, 1);
if (ret < 0) {
return ret;
}
return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_UNPIN, &pin));
}
3. 獲取大小
int ashmem_get_size_region(int fd)
{
int ret = __ashmem_is_ashmem(fd, 1);
if (ret < 0) {
return ret;
}
return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL));
}
因?yàn)槭俏募枋龇趟荆躁P(guān)閉直接采用close.
close(fd)
使用例子
創(chuàng)建共享內(nèi)存
fd = ashmem_create_region(NULL,length);
if(fd < 0)
printf("Creating code cache, ashmem_create_region error.");
將共享內(nèi)存映射到用戶空間
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));
}
關(guān)閉映射并關(guān)閉共享內(nèi)存文件
munmap(data,length);
close(fd);