Chinaunix首页 | 论坛 | 博客
  • 博客访问: 288966
  • 博文数量: 44
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 1354
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-08 15:38
个人简介

人生像是在跑马拉松,能够完赛的都是不断地坚持向前迈进;人生就是像在跑马拉松,不断调整步伐,把握好分分秒秒;人生还是像在跑马拉松,能力决定了能跑短程、半程还是全程。人生其实就是一场马拉松,坚持不懈,珍惜时间。

文章分类

分类: LINUX

2017-05-13 23:49:16

伙伴管理算法初衷是解决外部碎片问题,而slab算法则是用于解决内部碎片问题,但是内存使用的得不合理终究会产生碎片。碎片问题产生后,申请大块连续内存将可能持续失败,但是实际上内存的空闲空间却是足够的。这时候就引入了不连续页面管理算法,即我们常用的vmalloc申请分配的内存空间,它主要是用于将不连续的页面,通过内存映射到连续的虚拟地址空间中,提供给申请者使用,由此实现内存的高利用。

按照分析管理,从该管理算法的初始化入手。vmalloc_init()为vmalloc不连续内存管理初始化函数。具体实现:

  1. 【file:/mm/vmalloc.c】
  2. void __init vmalloc_init(void)
  3. {
  4.     struct vmap_area *va;
  5.     struct vm_struct *tmp;
  6.     int i;
  7.  
  8.     for_each_possible_cpu(i) {
  9.         struct vmap_block_queue *vbq;
  10.         struct vfree_deferred *p;
  11.  
  12.         vbq = &per_cpu(vmap_block_queue, i);
  13.         spin_lock_init(&vbq->lock);
  14.         INIT_LIST_HEAD(&vbq->free);
  15.         p = &per_cpu(vfree_deferred, i);
  16.         init_llist_head(&p->list);
  17.         INIT_WORK(&p->wq, free_work);
  18.     }
  19.  
  20.     /* Import existing vmlist entries. */
  21.     for (tmp = vmlist; tmp; tmp = tmp->next) {
  22.         va = kzalloc(sizeof(struct vmap_area), GFP_NOWAIT);
  23.         va->flags = VM_VM_AREA;
  24.         va->va_start = (unsigned long)tmp->addr;
  25.         va->va_end = va->va_start + tmp->size;
  26.         va->vm = tmp;
  27.         __insert_vmap_area(va);
  28.     }
  29.  
  30.     vmap_area_pcpu_hole = VMALLOC_END;
  31.  
  32.     vmap_initialized = true;
  33. }
    该函数先是遍历每CPU的vmap_block_queue和vfree_deferred变量并进行初始化。其中vmap_block_queue是非连续内存块队列管理结构,主要是队列以及对应的保护锁;而vfree_deferred是vmalloc的内存延迟释放管理,除了队列初始外,还创建了一个free_work()工作队列用于异步释放内存。接着将挂接在vmlist链表的各项__insert_vmap_area()输入到非连续内存块的管理中。


    其中__insert_vmap_area()的实现值得一读,这里面有几个比较关键的数据在这里。

  1. 【file:/mm/vmalloc.c】
  2. static void __insert_vmap_area(struct vmap_area *va)
  3. {
  4.     struct rb_node **p = &vmap_area_root.rb_node;
  5.     struct rb_node *parent = NULL;
  6.     struct rb_node *tmp;
  7.  
  8.     while (*p) {
  9.         struct vmap_area *tmp_va;
  10.  
  11.         parent = *p;
  12.         tmp_va = rb_entry(parent, struct vmap_area, rb_node);
  13.         if (va->va_start < tmp_va->va_end)
  14.             p = &(*p)->rb_left;
  15.         else if (va->va_end > tmp_va->va_start)
  16.             p = &(*p)->rb_right;
  17.         else
  18.             BUG();
  19.     }
  20.  
  21.     rb_link_node(&va->rb_node, parent, p);
  22.     rb_insert_color(&va->rb_node, &vmap_area_root);
  23.  
  24.     /* address-sort this list */
  25.     tmp = rb_prev(&va->rb_node);
  26.     if (tmp) {
  27.         struct vmap_area *prev;
  28.         prev = rb_entry(tmp, struct vmap_area, rb_node);
  29.         list_add_rcu(&va->list, &prev->list);
  30.     } else
  31.         list_add_rcu(&va->list, &vmap_area_list);
  32. }


    该函数主要动作先是遍历vmap_area_root红黑树(这是一棵根据非连续内存地址排序的红黑树),查找合适的节点位置,然后rb_insert_color()插入到红黑树中,最后则是查找插入的内存块管理树的父节点,有则插入到该节点链表的后面位置,否则作为链表头插入到vmap_area_list链表中(该链表同样是根据地址排序的)。

阅读(2914) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~