1.vmalloc分配器的使用:
vmalloc经常用于申请大块内存。由于kmalloc最大申请内存为4MB,如果想要申请更加大的内存,可以使用vmalloc,大小没有限制,虚拟地址连续,物理地址不一定连续。
vmalloc区域最小是240MB,这个是内核定义好的。当线性映射区较小时,会把多余的地址分给vmalloc。
kmalloc(最大申请4MB内存,因为它是直接从伙伴系统中申请内存的,伙伴系统中最大的内存块就是4MB)
vmalloc:申请的物理页帧是不是连续的,虚拟地址空间是已连续的。
2.编程实战:
static int __init hello_init(void)
{unsigned int phys_addr;unsigned int pfn;p = vmalloc(5*1024*1024);if(!p){printk("vmalloc fail!\n")}else{for(i=0; i<100; i++){p = p + 1024;//pfn = vmalloc_to_pfn(p);//转换成物理页帧,注意这里不能通过virt_to_phys转成物理地址,因为它是针对线性映射区phys_addr = (pfn << 12) | ((unsigned int)p&&0xff);printk("virt_addr: %x; pfn:%x; phys_addr:%x\n", (unsigned int p), pfn, (unsigned int)phys_addr);}}printk("-------------------------------\n");q = kmalloc(4*1024*1024,GFP_KERNEL);//4MB成功,5MB失败,从线性映射区申请的虚拟内存if(!q){printk("malloc fail\n");} else {for(i=0; i<100; i++){q = q + 1024;phys_addr = virt_to_phys(q);//转换成物理地址pfn = (unsigned long)phys_addr >> 12;printk("virt_addr: %x; pfn:%x; phys_addr:%x\n", (unsigned int p), pfn, (unsigned int)phys_addr);}}
}static void __exit hello_exit(void)
{vfree(p);kfree(q);
}module_init(hello_init);
module_exit(hello_exit);MODULE_LICESE("GPL";)
MODULE_DESCRIPTION("kmalloc/kfree demo");
3.内核源码解析vmalloc分配器
在内核层面,每次通过vmalloc申请一片区域,都会通过vmap_area结构体描述。申请的每个区域都会放到一个链表上和红黑树上(struct list_head list; struct rb_node rb_node;)vm_struct表示当前映射的区域。