-
分页的概念
- “分段“这一内存管理办法存在一个问题,就是内存空间会碎片化(fragmented)。
- 为了避免这些内存碎片的出现,出现了“分页”这一办法。
- “分页”并不将进程的地址空间分成几个不同长度的逻辑段(如代码、堆、栈),而是将进程分割为几个固定大小的单元,每个单元成为一页
- 同时,我们把物理内存视作一个定长槽块的阵列,每个槽块叫做“页帧(Page frame)”;我们也给虚拟内存中的每个页取名为虚拟内存页
-
进程与分页
-
操作系统通过页来维护进程的地址空间
- 一个进程会拥有一个或多个页
- 对于进程的虚拟地址,一个虚拟地址会包含虚拟页面号(Virtual page number, VPN) 和页内偏移量(Offset)
- 为了记录地址空间的每个虚拟页在物理内存中的位置,操作系统为每个进程都各自维护了一个页表,操作系统通过页表来完成从虚拟地址到物理地址的转换(translate)
-
从虚拟地址到物理地址的转换
- 页表中存储了每个虚拟页面号到物理帧号(PFN, Physical frame number, 也叫”物理页号“)的映射,也就是存储每个虚拟内存页到物理内存页帧的映射
- 当进程访问虚拟地址时:
- 首先操作系统检查目标虚拟地址的虚拟页面号,通过页表获取其对应的物理帧号
- 对于偏移量,物理内存和虚拟内存是一致的
- 然后将物理帧号和偏移量发送给物理内存,从而完成访问
-
-
页表
-
页表存储在哪里
- 相较于段表和基址/界限对,页表占用的空间非常大
- 由于页表太大了,我们不使用MMU来存储页表,而是直接将页表存在内存里
- 其实操作系统本身也可以有一部分运行在虚拟内存上,所以页表也可以运行在虚拟内存上,甚至实际可能交换到磁盘中,不过在这里先假设页表存储在物理内存上
-
页表的内容
- 页表是一个数据结构,用于将虚拟页号映射到物理帧号,每一个单元就是一个页表项(PTE, Page table entry)
- 实现页表最简单的形式是线性页表(Linear page table),也就是一个数组。操作系统通过虚拟页号作为索引检索数组,找到对应的页表项,并获得期望的物理帧号
- 每一个页表项中都有很多个部分,或者说很多个位:
- 有效位(Valid bit):用于指示这个地址转换是否有效。例如一个进程的代码与堆在地址空间的一端,栈在另一端,它们中间的这一部分就是无效的,访问无效部分会陷入操作系统
- 保护位(Protection bit):表明页是否可以读取、写入或执行。同样,执行不被允许的操作会陷入操作系统
- 存在位(Present bit):表示该页在物理存储器上,还是它已被换出(Swapped out),在磁盘上
- 脏位(Dirty bit):表示页被带入内存后是否被修改过
- 参考位(Reference bit)/访问位(Access bit):用于追踪页是否被访问了。也可以用于表示这个页受不受欢迎,因此应该留在内存中,这对于页面替换(Page replacement) 非常重要
-
-
分页的性能
- 页表不仅占用的空间很大,使用页表也会让速度变慢
- 对于一个进程,我们需要给它维护一个页表基址寄存器(Page-table base register) 来存储页表的起始位置的物理地址。这意味着对每个内存引用,分页都会需要我们多执行一次内存引用
- 显然,虽然分页可以避免外部碎片问题(仍然存在内部碎片问题),但是它还需要优化
操作系统 - Operating System
/
Chapter II 虚拟化
/
Section 2 内存虚拟化
/
2-2 分段与分页