主要内容:理解ChChor的内存管理方法和虚拟内存映射方法。
1. 内存布局
2. Buddy系统
物理页的内存管理方法,以4KB的page为单位。
一个物理page对应一个struct page的管理结构体。
以order为单位分配,对应1,2,4,8,16…个page。
每个order对应一个free_lists链表
在分配和释放时做merge和split的动作,避免浪费。
3. Slab系统
slab时建立在buddy system上的分配器,用于分配小于4KB的内存。操作系统里面的结构体大小常为几十、几百字节。
这里分析下ChChor里的使用的slab分配器。
首先,slab定义了一个全局数组:
1 | /* order range: [SLAB_MIN_ORDER, SLAB_MAX_ORDER] */ |
它只分配固定大小的size,分别是32,64,128…2048
3.1 slab分配器初始化
只能分配固定大小的obj,从32,64…到2048,每个大小的slab用全局数据管理
初始化时,先分配物理page(2MB),然后初始化物理页,按照obj大小划分为n个物理对象
第一个物理对象,用来存放slab_header,slab_header的free_list_head链表把所有的空闲对象串联起来;next_slab指向相同大小的下一个slab对象
3.2 slab内存分配
根据size找到对应的slab对象,超过2048则直接从buddy system分配page
首先从第一个slab_header分配,如果free_list_head为NULL,表示没有空闲的了,尝试从next_slab分配
如果都没有了,则重新向buddy system申请slab cache
3.3 slab内存释放
根据addr得到page
page的元数据区保存了slab的指针,找到slab对象
把该对象(slot节点)加到slab的free_list_head中
总结
- slab分配器是只slab,slub,slob等分配器家族。
- chcore中只实现了slab分配器,没有实现slub(没有current,partial,full等链表来加快分配过程)
- slab分配器中只看到了init_slab_cach,不够时一直从buddy system申请物理页,但是没有看到释放物理页,因此它会一直保持峰值时占用的物理内存,即使后面不再使用了。
4. 虚拟内存映射
虚拟内存映射简单来说是怎么根据虚拟地址得到真正的物理地址的过程。地址翻译的过程是由硬件MMU来自动完成的。
AArch64支持的物理内存地址空间的大小为48位,对应4级页表9位的页表索引(每个页表512个条目)+12位的页偏移(每页4KB大小)。
页表基地址寄存器:TTBR0_EL1(存储用户程序映射的页表)和TTBR1_EL1(存储内核映射的页表)。
AArch64页表的项被称为描述符。一共有三种:
- 表描述符:包含下一级页表的地址(next_table_address)和相应的属性。对应图20.3中的蓝色条目
- 块条目:L1 和 L2中可以存储块条目,对应1G的块和2M的块,pfn分别为18和27位,也就是常常说的大页
- 页条目:L3 页表中存储的是页条目,每个条目对应1个4K的块
分析几个主要的函数:
get_next_ptp :找到下一个页表的ptp(page table page)
1 | int get_next_ptp(ptp_t * cur_ptp, u32 level, vaddr_t va, |
map_range_in_pgtbl:给定页表基地址,把虚拟地址空间映射成物理地址空间。
1 | int map_range_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, paddr_t pa, |
query_in_pgtbl:根据pgtbl和va,得到pa(物理地址)和entry(页表条目里有属性)
1 | int query_in_pgtbl(vaddr_t * pgtbl, vaddr_t va, paddr_t * pa, pte_t ** entry) |