Ashmem 内存分析

来源:互联网 发布:js双引号转义字符 编辑:程序博客网 时间:2024/06/06 21:42

http://blog.csdn.net/long19851105/article/details/7287001

android中调用ashmem的地方很多,一个dalvik中的例子:

[cpp] view plaincopy
  1. void *dvmAllocRegion(size_t byteCount, int prot, const char *name) {  
  2.     void *base;  
  3.     int fd, ret;  
  4.   
  5.     byteCount = ALIGN_UP_TO_PAGE_SIZE(byteCount);  
  6.     fd = ashmem_create_region(name, byteCount);  
  7.     if (fd == -1) {  
  8.         return NULL;  
  9.     }  
  10.     base = mmap(NULL, byteCount, prot, MAP_PRIVATE, fd, 0);  
  11.     ret = close(fd);  
  12.     if (base == MAP_FAILED) {  
  13.         return NULL;  
  14.     }  
  15.     if (ret == -1) {  
  16.         return NULL;  
  17.     }  
  18.     return base;  
  19. }  

在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上的所有函数来回收内存。
[cpp] view plaincopy
  1. static int __init ashmem_init(void)  
  2. {  
  3.     ashmem_area_cachep = kmem_cache_create("ashmem_area_cache",  
  4.                       sizeof(struct ashmem_area),  
  5.                       0, 0, NULL);  
  6. ...  
  7.     ashmem_range_cachep = kmem_cache_create("ashmem_range_cache",  
  8.                       sizeof(struct ashmem_range),  
  9.                       0, 0, NULL);  
  10. ...  
  11.     ret = misc_register(&ashmem_misc);  
  12. ...  
  13.     register_shrinker(&ashmem_shrinker);  
  14.   
  15. ...  
  16. }
  1. static struct file_operations ashmem_fops = {  
  2.     .owner = THIS_MODULE,  
  3.     .open = ashmem_open,  
  4.     .release = ashmem_release,  
  5.         .read = ashmem_read,  
  6.         .llseek = ashmem_llseek,  
  7.     .mmap = ashmem_mmap,  
  8.     .unlocked_ioctl = ashmem_ioctl,  
  9.     .compat_ioctl = ashmem_ioctl,  
  10. };
  11. static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
  12. {  
  13.     struct ashmem_area *asma = file->private_data;  
  14.   
  15.     switch (cmd) {  
  16. ...  
  17.     case ASHMEM_PIN:  
  18.     case ASHMEM_UNPIN:  
  19.     case ASHMEM_GET_PIN_STATUS:  
  20.         ret = ashmem_pin_unpin(asma, cmd, (void __user *) arg);  
  21.         break;  
  22. ...  
  23. }
  24. static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,  
  25.                 void __user *p)  
  26. {  
  27. ...  
  28.     switch (cmd) {  
  29.     case ASHMEM_PIN:  
  30.         ret = ashmem_pin(asma, pgstart, pgend);  
  31.         break;  
  32.     case ASHMEM_UNPIN:  
  33.         ret = ashmem_unpin(asma, pgstart, pgend);  
  34.         break;  
  35. ...  
  36. }
主要用到的函数也就是ashmem_open\ashmem_mmap\以及ashmem_ioctl里面的ashmem_pin和ashmem_unpin.我们首先会调用ashmem_open来打开ashmem设备,然后调用ashmem_mmap来从tmpfs里面获取一块虚拟的内存空间.默认情况下,这块内存区域是完全pin住的, 当用户不需要某一子块时, 可以调用ashmem_unpin来讲这个ashmem_range加入到unpin list中,到系统内存紧缺时, 会调用ashmem_shrink函数,从unpin  
 list里面回收内存.记住,仅仅是回收物理内存,vma线性区还是存在的, 所以当用户想重新使用时, 调用ashmem_pin  
大概的过程就是这样, 各个模块的函数代码分析,其实网上很多,你自己认真看也很好理解,我嫌麻烦就不讲了.值得一提的是,目前android中,还没有什么模块调用了pin/unpin操作,也就是说,都是并没有使用这种内部管理内存的特性. 各位如果有兴趣的话,可以考虑对系统调用这些内存的地方尝试加入这种特性,最大限度的使用ashmem.

原创粉丝点击