Linux kernel之二内存管理之连续内存page fram
1.固定长度的物理内存管理技术-page frame 管理
- 用4KB page frame 作为基本的内存管理单元
- page frame 状态用页描述符 struct page
1)virt_to_page(addr) 产生与线性地址addr 关联的页描述符的地址
2)pfn_to_page(pfn) 产生与页号pfn的page frame 关联的页描述符的地址
-
mem_map 数组
1)描述所有的页
2)每个元素:32B, 整个table 小于内存的1% -
物理内存管理的管理架构
image.png
NUMA
UMA
-
非统一内存访问(NUMA )架构
image.png
1)一个CPU访问不同位置的内存的时间不一样;
2)物理内存划分成多个node;
3)一个特定的CPU 访问一个node 里的内存都是一样的;
4)不同CPU 访问一个node里的内存是不一样的;
5)内核申请内存时,会选择哪个CPU用的最频繁的内核数据结构,就申请哪个CPU的node的内存;
6)node 描述符:type pg_data_t
所有的node 描述符存在一个单向链表中,pgdat_list 指向第一个元素
-
UMA 架构
1)单个node, 包括所有系统物理内存
2)pgdat_list 指向一个list, 该list 由一个成员组成,Node 0,保存在contig_page_data 变量中 -
ZONE
1)每个node 内的内存划分成三个zone;
2)ZONE_NORMAL和ZONE_DMA 里的page frame 都能通过4th GB 的线性地址空间的线性映射访问
3)ZONE_HIGHMEML 里的page frame 不能直接访问,64位架构 没有
i. 高端内存没有线性地址
ii. 申请使用alloc_pages()和alloc_page()
iii. 没有线性地址的高端内存,内核不能访问;
xi. 最后128MB 的内核线性地址空间专门用于映射高端内存page frame;
x. 这种映射是零时的
ix. 映射高端内存的三种不同机制
永久内核映射
临时内核映射
非连续内存分配
4)每个zone 有自己的描述符 type zone
zone 类型 | 物理内存范围 |
---|---|
ZONE_DMA | 0~16MB 的page frame |
ZONE_NORMAL | 16MB ~896MB |
ZONE_HIGHMEML | 高于896MB 的page frame |
-
Node(NUMA/UMA) + ZONE + page frame
1)整个物理内存空间划分成多个node,所有的node 保存在一个单向链表
i.每个node 与对应的 CPU 关联,用一个pg_data_t 类型的实例管理;
ii. 每个个node 都有一个backup list,分配内存有限分配与对应CPU关联的node 的内存,当对应的node 用完了,会从backup list 对应的node中依次分配内存,越位于list后面的node,越不适合
2)每个node 的物理内存进一步划分成多个zone;
3)每个zone 中物理内存,划分成的固定大小的page frame;
每个page frame 用struct page 描述
2.page frame 的分配
- mem_map,ZONE,虚拟地址空间关系
1)虚拟地址空间划分:低3GB 空间用于用户空间,高1GB 用于内核地址空间
image.png
2)ZONE DMA 和ZONE_NORMAL 对应内核虚拟地址物理内存直接映射区,其虚拟地址到物理地址映射的PTE 已经建好了,虚拟地址与物理地址之间只相差(PAGE_OFFSET,即0xC0000000)
3)来自ZONE_HIGH 分配的page, 内核没有进行地址映射,需调用者在内核虚拟地址 Fixmaps 区或者动态映射区分配一个虚拟地址,然后映射到该物理page frame 上
image.png
4)ZONE_NORAML 和ZONE_DMA
image.png
- 申请page frame
1)alloc_pages
i.返回struct page
ii. 默认分配的物理内存来自ZONE_NORMAL 或ZONE_DMA
iii.若gdf_mask 指定__GFP_HIGHMEM, 则优先ZONE_HIGH
xi. 需调用地址转换函数
ZONE_DMA or ZONE_NORMAL: 可直接使用page_address
ZONE_HIGHMEM:
kmap 在内核动态映射区或固定映射区分配一个内核虚拟地址(KVA),并通过操作page table,将KVA映射到这个物理page frame 上
2) __get_free_pages
i. 返回内核线性地址(KVA)
ii. 不能用在高端内存分配
函数 | 含义 |
---|---|
alloc_pages(gfp_mask,order) | 请求2^order 的page frame,返回第一个页描述符 |
alloc_page(gfp_mask) | 请求一个的page frame,返回第一个页描述符 or NULL |
__get_free_pages(gfp_mask, order) | 类似alloc_pages,返回线性地址 |
_ _get_free_page(gfp_mask) | 返回单个page frame的线性地址 |
get_zeroed_page(gfp_mask) | 等同于alloc_pages(gfp_mask |__GFP_ZERO, 0) |
__get_dma_pages(gfp_mask, order) | 等同于__get_free_pages(gfp_mask| __GFP_DMA, order)| |
3.伙伴(buddy)分配系统
-
管理连续page frame 算法
-
被Linux用于避免外部碎片化
-
所有page frame 划分成11 个list
-
11 个list 将对应1, 2,4,8,16,32,64,128,256,512,1024个连续的page frame 链接到一起
image.png -
buddy system 和memory nodes, zone
i. 基于buddy system 的内存管理用在一个node 的一个zone 中;
ii.所有node,所有zone 的buddy system 通过fallback list 链接起来
image.png