http://blog.csdn.net/long19851105/article/details/7287001
android中调用ashmem的地方很多,一个dalvik中的例子:
- void *dvmAllocRegion(size_t byteCount, int prot, const char *name) {
- void *base;
- int fd, ret;
- byteCount = ALIGN_UP_TO_PAGE_SIZE(byteCount);
- fd = ashmem_create_region(name, byteCount);
- if (fd == -1) {
- return NULL;
- }
- base = mmap(NULL, byteCount, prot, MAP_PRIVATE, fd, 0);
- ret = close(fd);
- if (base == MAP_FAILED) {
- return NULL;
- }
- if (ret == -1) {
- return NULL;
- }
- return base;
- }
在create java虚拟机的时候,会先分配一块ashmem的内存给gc堆,然后虚拟机内部的进程调用malloc分配的内存都是从这块区域来分配的。
首先,调用 ashmem_create_region函数,分配一个ashmem_region,其实没有做什么事情,也就是打开了一下ashmem设备,设了一堆变量值。然后,调用mmap把区域映射到用户空间,就可以直接操作了。这个mmap最后会调用到ashmem的mmap,里面会调用到shm,通过tmpfs来分配一块内存区域。
ashmem的使用就是这么简单,下面我们来看看具体的驱动代码:系统启动的时候,会首先调用ashmem_init函数,这个函数里面,会注册ashmem_misc这个设备,已经注册ashmem_shrinker这个函数到shrink_list上去,当系统内存不足时,linux会依次调用list上的所有函数来回收内存。- static int __init ashmem_init(void)
- {
- ashmem_area_cachep = kmem_cache_create("ashmem_area_cache",
- sizeof(struct ashmem_area),
- 0, 0, NULL);
- ...
- ashmem_range_cachep = kmem_cache_create("ashmem_range_cache",
- sizeof(struct ashmem_range),
- 0, 0, NULL);
- ...
- ret = misc_register(&ashmem_misc);
- ...
- register_shrinker(&ashmem_shrinker);
- ...
- }
- static struct file_operations ashmem_fops = {
- .owner = THIS_MODULE,
- .open = ashmem_open,
- .release = ashmem_release,
- .read = ashmem_read,
- .llseek = ashmem_llseek,
- .mmap = ashmem_mmap,
- .unlocked_ioctl = ashmem_ioctl,
- .compat_ioctl = ashmem_ioctl,
- };
- static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
- struct ashmem_area *asma = file->private_data;
- switch (cmd) {
- ...
- case ASHMEM_PIN:
- case ASHMEM_UNPIN:
- case ASHMEM_GET_PIN_STATUS:
- ret = ashmem_pin_unpin(asma, cmd, (void __user *) arg);
- break;
- ...
- }
- static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
- void __user *p)
- {
- ...
- switch (cmd) {
- case ASHMEM_PIN:
- ret = ashmem_pin(asma, pgstart, pgend);
- break;
- case ASHMEM_UNPIN:
- ret = ashmem_unpin(asma, pgstart, pgend);
- break;
- ...
- }
list里面回收内存.记住,仅仅是回收物理内存,vma线性区还是存在的, 所以当用户想重新使用时, 调用ashmem_pin
大概的过程就是这样, 各个模块的函数代码分析,其实网上很多,你自己认真看也很好理解,我嫌麻烦就不讲了.值得一提的是,目前android中,还没有什么模块调用了pin/unpin操作,也就是说,都是并没有使用这种内部管理内存的特性. 各位如果有兴趣的话,可以考虑对系统调用这些内存的地方尝试加入这种特性,最大限度的使用ashmem.