伙伴管理算法初衷是解决外部碎片问题,而slab算法则是用于解决内部碎片问题,但是内存使用的得不合理终究会产生碎片。碎片问题产生后,申请大块连续内存将可能持续失败,但是实际上内存的空闲空间却是足够的。这时候就引入了不连续页面管理算法,即我们常用的vmalloc申请分配的内存空间,它主要是用于将不连续的页面,通过内存映射到连续的虚拟地址空间中,提供给申请者使用,由此实现内存的高利用。
按照分析管理,从该管理算法的初始化入手。vmalloc_init()为vmalloc不连续内存管理初始化函数。具体实现:
-
【file:/mm/vmalloc.c】
-
void __init vmalloc_init(void)
-
{
-
struct vmap_area *va;
-
struct vm_struct *tmp;
-
int i;
-
-
for_each_possible_cpu(i) {
-
struct vmap_block_queue *vbq;
-
struct vfree_deferred *p;
-
-
vbq = &per_cpu(vmap_block_queue, i);
-
spin_lock_init(&vbq->lock);
-
INIT_LIST_HEAD(&vbq->free);
-
p = &per_cpu(vfree_deferred, i);
-
init_llist_head(&p->list);
-
INIT_WORK(&p->wq, free_work);
-
}
-
-
/* Import existing vmlist entries. */
-
for (tmp = vmlist; tmp; tmp = tmp->next) {
-
va = kzalloc(sizeof(struct vmap_area), GFP_NOWAIT);
-
va->flags = VM_VM_AREA;
-
va->va_start = (unsigned long)tmp->addr;
-
va->va_end = va->va_start + tmp->size;
-
va->vm = tmp;
-
__insert_vmap_area(va);
-
}
-
-
vmap_area_pcpu_hole = VMALLOC_END;
-
-
vmap_initialized = true;
-
}
该函数先是遍历每CPU的vmap_block_queue和vfree_deferred变量并进行初始化。其中vmap_block_queue是非连续内存块队列管理结构,主要是队列以及对应的保护锁;而vfree_deferred是vmalloc的内存延迟释放管理,除了队列初始外,还创建了一个free_work()工作队列用于异步释放内存。接着将挂接在vmlist链表的各项__insert_vmap_area()输入到非连续内存块的管理中。
其中__insert_vmap_area()的实现值得一读,这里面有几个比较关键的数据在这里。
-
【file:/mm/vmalloc.c】
-
static void __insert_vmap_area(struct vmap_area *va)
-
{
-
struct rb_node **p = &vmap_area_root.rb_node;
-
struct rb_node *parent = NULL;
-
struct rb_node *tmp;
-
-
while (*p) {
-
struct vmap_area *tmp_va;
-
-
parent = *p;
-
tmp_va = rb_entry(parent, struct vmap_area, rb_node);
-
if (va->va_start < tmp_va->va_end)
-
p = &(*p)->rb_left;
-
else if (va->va_end > tmp_va->va_start)
-
p = &(*p)->rb_right;
-
else
-
BUG();
-
}
-
-
rb_link_node(&va->rb_node, parent, p);
-
rb_insert_color(&va->rb_node, &vmap_area_root);
-
-
/* address-sort this list */
-
tmp = rb_prev(&va->rb_node);
-
if (tmp) {
-
struct vmap_area *prev;
-
prev = rb_entry(tmp, struct vmap_area, rb_node);
-
list_add_rcu(&va->list, &prev->list);
-
} else
-
list_add_rcu(&va->list, &vmap_area_list);
-
}
该函数主要动作先是遍历vmap_area_root红黑树(这是一棵根据非连续内存地址排序的红黑树),查找合适的节点位置,然后rb_insert_color()插入到红黑树中,最后则是查找插入的内存块管理树的父节点,有则插入到该节点链表的后面位置,否则作为链表头插入到vmap_area_list链表中(该链表同样是根据地址排序的)。
阅读(2990) | 评论(0) | 转发(0) |