linux内核中不连续页分配器
Posted 为了维护世界和平_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux内核中不连续页分配器相关的知识,希望对你有一定的参考价值。
目录
当设备长时间运行,内存碎片化,很难找到连续的物理页。在这种情况下,如果需要分配长度超过一页的内存块,可以使用不连续页分配器,分配虚拟地址连续但是物理地址不连续的内存块。
在32位系统中,不连续页分配器有一个好处:优先从高端内存区域分配,保留稀缺的低端内存区域。
不连续页分配器编程接口
- vmalloc:分配不连续的物理页并且把物理页映射到连续的虚拟地址空间
- vfree:释放vmalloc分配的物理页和虚拟地址空间
- vmap:把已经分配的不连续物理页映射到连续的虚拟地址空间
- vunmap:释放使用vmap分配的虚拟地址空间
- kvmalloc函数:尝试先使用kmalloc分配内存块,如果失败,那么使用vmalloc函数分配不连续的物理页。
- kfree函数 释放使用kvmalloc申请的内存。
vmalloc虚拟地址空间的范围是[VMALLOC_START,VMALLOC_END)
ARM64架构下的VMALLOC_START,VMALLOC_END宏如下
/*
* VMALLOC range.
*
* VMALLOC_START: beginning of the kernel vmalloc space
* VMALLOC_END: extends to the available space below vmemmap, PCI I/O space
* and fixed mappings
*/
#define VMALLOC_START (MODULES_END)
#define VMALLOC_END (- PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
其中
- MODULES_END是内核模块区域的结束地址
- PAGE_OFFSET是线性映射区域的起始地址
- PUD_SIZE是一个页上层目录表项映射的地址空间长度
- VMEMMAP_SIZE是vmemmap区域的长度
vmalloc虚拟地址空间的起始地址等于内核模块区域的结束地址;
vmalloc虚拟地址空间的结束地址等于(线性映射区域的起始地址-一个页上层目录表项映射的地址空间长度-vmemmap区域长度-64KB)
vmalloc分配的是页,如果请求分配的长度不是页的整数倍,那么把长度对齐到页的整数倍。建议:在申请内存超过一页的时候吃药vmalloc。
每个虚拟内存区域对应一个vmap_area实例,每个vmap_area实例关联一个vm_struct实例
vmalloc执行过程
1)分配虚拟内存区域
分配vm_struct实例和vmap_area实例,然后遍历已经存在的vmap_area实例,在两个相邻的虚拟地址内存区域之间找到一个足够大的空间,如果找到了,把起始虚拟地址和结束虚拟地址保存在vmap_area实例中,然后把vmap_area实例加入到红黑数和链表。最后把新的vmap_area实例关联到vm_struct实例。
2)分配物理页
vm_struct实例的成员nr_pages存放页数n,分配page指针数组,数组大小是n,vm_struct实例的成员pages指向page指针数组;然后指向n次,从页分配器中分配一个物理页,把物理页对应的page实例的地址存放在page指针数组中。
3)在内核页表中把虚拟地址映射到物理地址页
内核的页表就是0号线程的页表。0号内核线程的进程描述符是全局变量init_task,成员active_mm指针指向全局变量init_mm,init_mm成员pgd指向页全局目录swapper_pg_dir。
参考链接
https://course.0voice.com/v1/course/intro?courseId=2&agentId=0
以上是关于linux内核中不连续页分配器的主要内容,如果未能解决你的问题,请参考以下文章
Linux 内核 内存管理内存管理架构 ③ ( Linux 内核中的内存管理模块 | 页分配器 | 不连续页分配器 | 内存控制组 | 硬件设备内存管理 | MMU | 页表缓存 | 高速缓存 )