引言:

ASHMEM = Android shared memory, 由Goolge 設計的一種記憶體分享、分配機制,主要用於 Google 設計給 Android 使用的 IPC Binder。

主要的driver 可在 aosp 的 kernel/mm/ashmem.c 找到實作,user space 的部份則是主要在 IMemory 裡面處理。

下面是從網路上收集的資訊:

 

 


Android ashmem的實現方式

來源: http://blog.sina.com.cn/s/blog_606334a20100goei.html

ashmem是android的內存分配/共享機制,在dev目錄下對應的設備是/dev/ashmem,相比於傳統的內存分配機制,如malloc、anonymous/named mmap,其好處是提供了輔助內核內存回收算法的pin/unpin機制。


ashmme的典型用法是先打開設備文件,然後做mmap映射。

第一步通過調用ashmem_create_region函數,這個函數完成這幾件事:

1)fd = open("/dev/ashmem", O_RDWR);
2)ioctl(fd, ASHMEM_SET_NAME, region_name); // 這一步可選
3)ioctl(fd, ASHMEM_SET_SIZE, region_size);

第二步,應用程序一般會調用mmap來把ashmem分配的空間映射到進程空間:

mapAddr = mmap(NULL, pHdr->mapLength, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);

應用程序還可以通過ioctl來pin和unpin某一段映射的空間,以提示內核的page cache算法可以把哪些頁面回收,這是一般mmap做不到的。

可以說ashmem以較小的代價(用戶需進行額外的ioctl調用來設置名字,大小,pin和unpin),獲得了一些內存使用的智能性。

ashmem本身實現也很小巧,只有不到700行。原因是借助了內核已經有的工具,例如shmem_file_setup(支撐文件),cache_shrinker(slab分配算法的頁面回收的回調函數)等。

如果ashmem不使用內核驅動實現,則pin/unpin的語義比較難以實現,或者即使實現,效率也不會很高。但查詢android源碼,使用pin/unpin很少,看來ashmem還是沒有很好地用起來。

如果不使用ashmem驅動,並且捨棄pin/unpin語義,那麼模擬ashmem的語義還是很簡單的。首 先,ashmem_create_region可以為進程創建一個唯一的文件(如進程名+時戳),打開,然後返回這個文件的fd;接著應用程序可以進性一 般的mmap操作了。如果不使用ashmem_create_region接口函數,那麼使用anonymous的mmap就可以了,但這種方式屬於正在 被丟棄的方式,而且並不是所有的系統都支持,比如Macos就不支持。

 

Android ashmem 語義的實現

來源: http://blog.sina.com.cn/s/blog_606334a20100gp7q.html

ashmem非常像是anonymous mmap,這或許是它的名字的由來吧。網上有人問pin和unpin到底是做什麼用的,似乎沒人回答。簡單的回答是:沒什麼用。深沉點的回答是:可以用來更有效地使用內存。具體講,當你覺得用ashmem分配的空間有部分似乎不大用得著時,你可以unpin這一塊空間,unpin後,內核可以把它對應的物理頁面回收,挪作他用。你並不用擔心以後進程對unpin的空間的訪問,因為回收了的內存,你還可以再次獲得(通過缺頁handler),因為unpin操作並不改變已經mmap的地址空間。所以說,pin/unpin純粹是內核內部的操作,不影響上層應用的語義。

如果不用ashmem驅動,不考慮pin/unpin語義,並且考慮到現有API的持續性(ashmem_create_region等),實現ashmem的語義雖然概念上不難,但還是有一些細節需要注意。

首先,ashmem不是用於進程間共享數據的,這是由驅動實現決定的。驅動把ashmem分配的地址空間賦給file結構的private,這就排除了進程間共享的可能性。

其次,ashmem的作用等同於anonymous mmap,純粹作分配空間用,你打開多少次/dev/ashmem設備(並mmap),你就獲得多少次(不同的)空間。這在同一個進程也是一樣的。這一點很重要。

舉例來說:
fd1 = open("/dev/ashmem", O_RDWR);
addr1 = mmap(0, size, ..., fd1, ...);
fd2 = open("/dev/ashmem", O_RDWR);
addr2 = mmap(0, size, ..., fd2, ...);

即使在同一個進程內,addr1和addr2也是不同的。用/dev/zero達不到這個效果,普通文件也不行。

所以,在使用普通文件模擬ashmem行為時,必須給每個文件起唯一的名字。這個技術可有很多選擇,比如使用開機後經歷的時間作為文件名的一部分。

huenlil 發表在 痞客邦 PIXNET 留言(0) 人氣()