kernel阅读手记之vmalloc

vmalloc kmalloc 的在逻辑地址上时连续的,他们的区别在于 vmalloc 在物理地址上并不时连续的,但是 kmalloc 在物理地址上页时连续的。 Vmalloc 分配分为两种模式,一种是没有 MMU(memory management unit, 内存管理模块 ) vmalloc ,比如在 arm7 上,另一种则是在有 MMU 上的 vmalloc

 

在没有 MMU 模块支持的 cpu 上, vmalloc 则是调用的 slab 中的 kmalloc 实现的内存分配,其标志为 (gfp_mask | __GFP_COMP) & ~__GFP_HIGHMEM

 

在有 MMU 模块的体系架构中的 vmalloc() ,则是通过 __vmalloc_node() 来分配连续逻辑内存

__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,int node, void *caller) 的基本流程如下:

1、  错误处理,当待分配的大小为 0 ,或者将 size/ 页面大小 大于 num_physpages 时,返回空

2、  尝试调用 __get_vm_area_node() 获得虚拟内存空间的节点,失败则返回 null

3、  返回 __vmalloc_area_node(area, gfp_mask, prot, node, caller); 的返回值

 

__vmalloc_area_node(area, gfp_mask, prot, node, caller)

1、  nr_pages 设置成 vmalloc 需要的线形地址的页面数量

2、  设置 array_size 成线形地址的页面所需要的指针空间的大小

3、  nr_page 交给 area->nr_pages

4、  array_size 大于页面大小时,调用 __vmalloc_node(array_size, gfp_mask | __GFP_ZERO,PAGE_KERNEL, node, caller) 分配空间给 area->pages 。否则,将 kmalloc_node(array_size,(gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO,node) 赋值给 area->pages

5、  caller 的值传给 area->caller

6、  如果 area->pages 分配时,移除 area->addr 中的地址,并且释放 area ,返回 null

7、  遍历刚分配的页面,当 node 为负数时,采用 alloc_page(gfp_mask) page 分配空间,或者,则利用 alloc_pages_node(node, gfp_mask, 0) 。分配失败时,将 area->nr_pages 的值设置成 i ,释放掉 area->addr 中地址的使用权,返回 null. area_page[i] 设置成刚申请成功的内存页面。当 map_vm_area(area, prot, &pages) 成功映射,返回 area->addr ,否则释放掉 area_addr ,并返回空值。

 

在第七步可以知道, vmalloc 在对内存进行分配的时候不是“慷慨”的一次性将内存给分配完,而是采用一个循环的方式,多次调用 alloc_page() 或者 alloc_page_node 对内存进行分配。这样或许可以更加充分的利用内存,一些零碎的小内存单元可能被利用,但是在速度上就相对于 kmalloc 的速度要慢不少。 Kmalloc 针对内存紧张的小内存单元页有相应的 slob 的分配方式,甚至在一些不支持 MMU 的设备上 vmalloc 等同于 kmalloc 。所以我个人认为在实际内核编码过程中,更多的使用 kmalloc 会好些。

你可能感兴趣的:(null)