OSTEP学习笔记-分页
setmentation
因为使用动态大小的区块划分会不可避免地带来碎片问题。于是就有了第二种方式,分页。将内存分割了一组固定大小的page frame
,每一个frame
可包含一个虚拟内存空间中的page
。
分页的最大优势可能是灵活性,能高效地支持内存地址抽象,不用关心进程如何使用内存。另一个优势则是自由空间的管理。
OS维护一个per-process
的结构page table
,保存着虚拟page映射到物理frame的地址翻译。
地址翻译
将虚拟内存地址分割为virtual page number
(VPN)和offset两部分。前者代表page号,后者为page内偏移量。通过page table将VPN替换为对应的physical frame number
(PFN),从而可以得到真实的物理地址。
对于一个真实的32位系统,page大小为4K,那么VPN数量为2^20 = 1MB,假设每个page需要4byte信息,那么每个page table大小为4M, 如果系统中有100个进程,那么光page table就要消耗400MB空间。显然这个大小是不可能置于CPU寄存器的,只能放置在内存中(依然很大)。
Page Table Entry (PTE)
最简单的形式就是linear page table
,用一人数组来存储,其中下标为VPN,内容为PTE。
关于部分字母含义见下。
- valid标识。
将进程堆与栈间空白的所有page都标识为invalid,从而无需为之分配frame,节省了内存空间。 - protection bit(R/W)。
读写执行(rwx)标识,如果非法操作就会触发到达OS的trap。 - present bit(P)
位于内存or磁盘 - dirty(D)bit/reference(access) bit(A)
载入内存后是否被修改/存取。后者可以用于衡量page的popularity - U/S
User / supervisor 权限,user mode是否可存取
开销
大体过程如下
- 计算PTE地址。通过位移得到VPN,再
VPN*sizeof(PTE)
- 计算实际地址。
PTE.PFE << PFE_SHIFT | (VA &OFFSET_MASK)
当然实际还包含一些标识位的校验。
translation-lookaside buffer(TLB)
要想page可行,必须地址翻译铁够快。和往常一样,这同样是由硬件支持来实现的,MMU中添加address-translation cache来进行翻译工作,甚至不需要参考page table.
TLB基本算法
- 查TLB是否保存了当前VPN的翻译PTE,如果是则从中取出PFN,位移page位长后再并加上Offset就得到了物理地址PA。
- 如果未有对应PTE,则需要从page table中取出并更新TLB,再次执行1。(不仅要读取内存,且有额外操作,开销较大)
所以TLB如果要效率高,就必须缓存的PTE命中率必须高。
那么TLB miss时谁来处理?即可以是硬件也可以是软件(OS)。CISC的x86是硬件完全的,只需要设定page table的起始地址到指定寄存器。而RISC的MIPS等是由软件实现的,当miss发生时,cpu保存当前PC(更新tlb后会retry)并产生trap返回到OS处理。
软件实现具有简单、灵活的特点。
TLB结构
TLB中保存有32、64、128不等的条目,它们fully associative
, 可以并行地查找。条目内容如下:
VPN | PFN | other bits
context switch时TLB的处理
因为page table
是每进程不同的,所以在环境切换时一定确保二者不混淆。最简单的办法是切换时清除TLB,硬件架构可以通过重设page table base register实现。
也可以在TLB中添加ASID address space identifier,或者理解为进程ID,这样可以同时保存多个进程的PTE而不致混淆,但是同时CPU必须知道当前运行的进程ID,所以环境切换时必须设定相应的寄存器。
现实中的TLB
图中的是MIPS R4000
的TLB Entry
, 32bit寻址,page大小4kb,也就是1M个page,实际TLB中VPN却只有19位,因为只有一半user process可用,另一半归于OS。
PFN却有24位,因而支持64GB的物理内存。G代表此地址是所有进程共享的如code share
等。ASID只有8位;共有32或者64个这样的entry,少部分是OS专有的,用来指向关键的代码和数据如TLB miss时的处理等。
CPU同时提供一些配套的指令来操作TLB,如TLBP查找指定条目,TLBR读取条目内容、TLBWI修改指定条目等,当然这些指令也都是kernel mode才有权限执行的。
RAM并非RAM
RAM的意义为读取任意地址速度相同,但是通过page和TLB虚拟化之后,这一特性并不100%成立了,特别是当频繁跨度很大的操作地址时,开销可能会意外地大。