非连续内存分配(Noncontiguous Memory Allocation)
Linux中虚拟地址空间VMALLOC_START和VMALLOC_END之间保留了一块区域,VMALLOC_START的位置取决于可访问的物理内存大小,大小至少VMALLOC_RESERV(x86上位127MB)。该区域的页表可以按照请求修改,指向物理页分配器分配的物理页。意味着分配的大小必须是硬件页面大小的整数倍。分配器需要修改内核页表,且只有VMALLOC_START到VMALLOC_END之间的虚拟内存可以作映射,所以vmalloc()可用的内存是很有限的,以至于vmalloc()只能在内核态使用。在2.4.22中,只能用于存储swap map information和将内核模块加载到内存。
描述Virtual Memory Areas
vmalloc address space被resource map allocator管理。struct vm_struct负责存储base, size pairs。
struct vm_struct {
unsigned long flags; //使用vmalloc()时设置VM_ALLOC;使用ioremap()映射高端内存到内核虚拟地址空间时,设置VM_IOREMAP
void * addr; //内存块的起始地址
unsigned long size; //以字节为单位的内存块大小
struct vm_struct * next; //指向下一个vm_struct的指针。they are orderd by address, and the list is protected by vmlist_lock lock.
};
a fully-fledged VMA could have been used but it contains extra information that does not apply to vmalloc areas and would be wasteful.
为了防止overruns,每个区域最少用一个页面分隔开,如下图所示。
内核要分配一块新的内存时,get_vm_area() 线性查找vm_struct链表,然后由kmalloc()分配结构体所需的空间。当虚拟区域用作remapping以完成IO时,系统将直接调用该函数完成请求区域的映射。
分配非连续区域
Linux提供vmalloc(), vmalloc_dma() and vmalloc_32()在连续的虚拟地址空间分配内存。只有一个参数size,四舍五入到和下一个页面对齐。返回新分配区域的线性地址。
vmalloc()调用图如下所示:
vmalloc()更新的页表不属于当前进程。当前进程访问vmalloc区域时将发生缺页中断一场,因为它的页表没有指向正确的区域。缺页中断处理程序知道在vmalloc区域有个缺页中断,它利用主页表的信息更新当前进程的页表。使用vmalloc()处理伙伴分配器以及缺页中断的方法如下图所示。
释放非连续区域
vfree()负责释放一块虚拟内存区域。vfree()线性查找vm_struct链表,找到需要释放的区域后调用vmfree_area_pages()。
vmfree_area_pages()遍历页表,释放该区域的页表项和相应的页面。
参考文献:
[1] 白洛. 深入理解Linux虚拟内存管理. 2006-1
[2] Mel Gorman. Understanding the Linux Virtual Memory Manager. 2004-5-9