• [Linux内存]vmalloc学习笔记


    一:vmalloc
    http://www.360doc.com/content/14/0614/13/18127083_386524093.shtml
    1,vmalloc()的内核入口函数是kernel/mm/Vmalloc.c里的void *vmalloc(unsigned long size),size表示的是请求内核分配的字节数目。

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. void *vmalloc(unsigned long size)  
    2. {  
    3.  return __vmalloc_node_flags(size,-1,GFP_KERNEL|__GFP_HIGHMEM);  
    4. }  


    从以上代码可知,vmalloc()主要是从高端内存区域去分配内存。
    vmalloc()函数最终会调用到__vmalloc_node_range(unsigned long size,unsigned long align,unsigned long start,unsigned long end,gfp_t gfp_mask,,,,)函数
    以上函数size表示的是具体分配的字节的大小,align表示对齐的大小,默认为1,start和end分别表示vmalloc分区区域的起始地址和结束地址,arm体系结构上默认如下:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #define VMALLOC_OFFSET (8*1024*1024)  
    2. #define VMALLOC_START (((unsigned long)high_memory+VMALLOC_OFFSET)&~(VMALLOC_OFFSET-1))  
    3. #define VMALLOC_END 0Xff000000UL   //4080M  


    __vmalloc_node_range所做的事情如下:
    1. 首先检查请求分配的内存大小有没有超过最大的物理页面数。如果超过返回0,表示分配失败。
           size = PAGE_ALIGN(size);
           if (!size || (size >> PAGE_SHIFT) > num_physpages)
                  return NULL;
    2,调用__get_vm_area_node()函数,
     该函数作用,使用kmalloc在slab中,分配vm_struct数据结构。

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. area = kmalloc_node(sizeof(*area), GFP_KERNEL, node);  
    2. uct vm_struct {  
    3. void               *addr; // 虚拟地址的开始  
    4. unsigned long         size; // 分配大小  
    5. unsigned long         flags; // 标志位  
    6. struct page            **pages; // 对应的页面  
    7. unsigned int           nr_pages; // 页面数量  
    8. unsigned long         phys_addr; // 物理地址  
    9. struct vm_struct    *next; // 单链表,指向下一个vm节点  


     接下来在单链表vmlist中查找适合的位置,并将新的vm节点插入到单链表中。

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. for (p = &vmlist; (tmp = *p) != NULL ;p = &tmp->next) {  
    2.        if ((unsigned long)tmp->addr < addr) {  
    3.               if((unsigned long)tmp->addr + tmp->size >= addr)  
    4.                      addr = ALIGN(tmp->size +  
    5.                                  (unsigned long)tmp->addr, align);  
    6.               continue;  
    7.        }  
    8.        if ((size + addr) < addr)  
    9.               goto out; // 地址越界  
    10.        if (size + addr <= (unsigned long)tmp->addr)  
    11.               goto found; // 查找成功。进行插入操作  
    12.        addr = ALIGN(tmp->size + (unsigned long)tmp->addr, align);  
    13.        if (addr > end - size)  
    14.               goto out; // 地址越界  
    15. }  
    16. // 插入新的vm节点到vmlist中去。  
    17. area->next = *p;  
    18. *p = area;  
    19. // 初始化新结点  
    20. area->flags = flags;  
    21. area->addr = (void *)addr;  
    22. area->size = size;  
    23. // 物理内存还未分配。  
    24. area->pages = NULL;  
    25. area->nr_pages = 0;  
    26. area->phys_addr = 0;  


    3,调用__vmalloc_area_node()函数
      接下来初始化vm_struct结构中的pages和nr_pages字段。
     a)         初始化nr_pages字段
          nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
     b)        初始化pages数组
     计算数组大小
         array_size = (nr_pages * sizeof(struct page *));
     如果数组大小大于1个页面,在非连续区进行分配,否则在连续区进行分配

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1.     if (array_size > PAGE_SIZE)  
    2.      pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node);  
    3.     else  
    4.      pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node);  
    5. area->pages = pages;  


     从伙伴系统中进行物理内存页面的分配

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. for (i = 0; i < area->nr_pages; i++) {  
    2.        if (node < 0)  
    3.               area->pages[i] = alloc_page(gfp_mask); // 针对UMA  
    4.        else  
    5.               area->pages[i] = alloc_pages_node(node, gfp_mask, 0); // 针对NUMA  
    6.        if (unlikely(!area->pages[i])) {  
    7.               /* Successfully allocated i pages, free them in __vunmap() */  
    8.               area->nr_pages = i;  
    9.               goto fail;  
    10.        }  
    11. }  


        最后根据实际申请到的物理内存情况建立页表映射。刷新TLB标志
    4,调用insert_vmalloc_vmlist()函数
        将vm_struct结构体插入到vmlist链表中
    5,调用kmemleak_alloc()函数。

  • 相关阅读:
    java—在maven项目中配置selenium运行环境
    java—Maven安装配置
    java基础—异常处理
    java基础—IO流
    怎么查看chrome网络日志
    http缓存之304 last-modified,cache-control:max-age,Etag等
    dubbo源码分析7-dubbox怎么对dubbo做了扩展
    SQLite如何测试
    New line
    ElasticSearch 入门笔记1
  • 原文地址:https://www.cnblogs.com/zhiliao112/p/4251217.html
Copyright © 2020-2023  润新知