内存管理分为连续物理内存和非连续内存区管理: 连续内存管理1. 页描述符 Page记录了每一个页框的状态信息,所有的页描述符存放在mem_map数组中。 2. 节点(node)-> 内存管理区(zone)-> 页描述符page->物理页 Node:是针对NUMA模型设计的,一般情况下都是UMA模型,所以节点也就一个 Zone:在一个节点下有很多管理区, ZONE_DMA 包含低于16MB的内存页框 ZONE_NORMAL 包含高于16MB且低于896MB的内存页框 ZONE_HIGHMEN 包含从896MB开始高于896MB的内存页框 ZONE_DMA和ZONE_NORMAL包含内存的常规页框,通过内核可以直接转换访问。 ZONE_HIGHMEM包含的内存页不能由内核直接访问,尽管他们线性地址是映射到第4G的最后128M地方。 注意:node zone page 物理页之间的关系 node通过zone_t[]管理所有zone, zone通过active_list、inactive_list管理页描述符page page通过其内的flags字段的最高位来索引zone_table数组找到zone page通过页号Pfn来与物理页建立关联。Pfn<<4K即可得到物理地址 高端内存页框的内核映射页目录项还是不变的都是swapper_pg_dir,这个一直没变,高端映射只是添加了几个页表。 1. 我们知道线性地址的最后128M用来映射高端内存,那么有几种方法映射呢? 答: 有三种不同的机制,永久内核映射,临时内核映射,非连续内存分配 (1) 永久内核映射 当然首先也是需要一个页表,pkmap_page_table 通过调用kmap就可以建立与固定页的映射,过程是在pkmap_page_table页表中查找一个空闲表项,然后填充该页的物理地址建立映射,注意如果找不到空闲项就必须阻塞当前进程等待其他进程释放了表项。 (2) 临时内核映射 临时内核的页表放在kmap_pte中,系统调用为kmap_atomic和kunmap_atomic 在临时内核映射中,每一个CPU有自己单独的一部分线性地址,在每个CPU内部的线性地址中又根据ktype划分成好几部分(每一部分对应一个物理page)的线性地址,所以当索引里面的表项时,可以用下面的公式: 每一个CPU块的起始地址=起始地址+KM_TYPE的数量*CPU的编号 根据你要求的km_type,再加上每块内的索引即可获得具体的线性地址。 这些临时映射的线性地址,主要用来存放固定的指针引用,一般初始化后不再修改。 问题:固定映射和临时内核映射的关系? 答:固定映射包含临时内核映射的线性地址空间,具体关系为:
固定映射的线性地址都由定义于enum fixed_addresses枚举数据结构中的整型索引来表示。 (3) 非连续分配内存 当对内存的请求不是很频繁,通过连续的线性地址来访问非连续的页框这样一种分配模式就很有意义,其主要优点是避免了外碎片,而缺点是必须打乱内核页表。 VMALLOC_START—-VMALLOC_END 非连续分配线性地址区 PKMAP_BASE—-FIXADDR_START 永久内核映射线性地址区 FIXADDR_START——END 固定内核映射线性地址区(临时内核映射) 组织方式: 与线性地址分配类似,将线性地址区组织成AVL树(目的是查找速度快)。 Vmstruct 通过addr字段与AVL树种的节点(vm_area)建立联系。 通过page指向实际分配的物理页的页描述符。 分配过程: 1. 调用get_vm_area从已经准备好的AVL树种查找该区间,如果该区间没有被使用,就将该区间作为vm_area节点插入到AVL树中,否则返回找到的节点。然后将分配好的vm_struct的addr指向该vm_area,并将vm_struct插入到vmlist的链表中。 2. 为vm_struct的pages分配页描述符数组pages[],循环调用alloc_page分配物理页与pages[i]建立联系。 3. 修改页表 |
|