操作系统-段页式管理
[!cite] > 4.1 为什么要有虚拟内存? | 小林coding
1. 分段 Segmentation
- 分段是最早时期提出的内存管理的方法之一,其所谓的“段”,是逻辑意义上的段,譬如“代码段”、“数据段”、“堆段”、“栈段”等等,每一个段,都对应逻辑意义上一个功能区域。
- 段内是连续的,但是段和段之间,并非连续,其概览如下图。
- 从虚拟地址到实际地址,段通过“段表”维护了虚拟内存和物理地址之间的映射。
- 换言之,通过段基地址和偏移量,就可以计算出具体的物理地址。
- 分段的好处在于逻辑意义清晰,而且一定程度上确实实现了资源的隔离和硬件资源的访问控制
- 但是依然存在一些弱点,其比较显著的两大缺陷如下:
- 内存碎片的问题
- 内存交换的效率不足
1.1 段式管理的内存碎片
- 内存碎片可以分成内部和外部两种,所谓内部碎片,就是碎片产生在连续内存空间的内部,外部碎片即碎片产生在连续内存空间的外部。
- 段式管理基本上不会产生内部碎片,但是其基于逻辑的划分方式,会导致外部碎片的产生,因为一段连续地址可能被段式管理分成很多截了,如果其中某一截回收,其他空间也无法连续。
- 其原理如下图所示
1.2 段式管理降低效率
- 为了解决内存碎片的问题,常见的策略就是使用
swap
来扩展逻辑意义上可以利用的内存空间。 - 但是段式管理,每次
swap
的都是一个很大的逻辑段,IO
的负担比较大,每次都要把一大块容量写到磁盘上,其效率自然不会高。
2. 分页管理 Paging
2.1 分页管理的基本思想
- 基本思想很简单:化整为零,不再做逻辑意义上的区分(有点类似于曹冲称象)
- 将整个内存空间,全部切分成原子化的单位(比如
Linux
系统就是4KB
大小的内存块),然后将原子化的单位和逻辑意义上的地址做一一映射,形成所谓的“虚拟内存”。 - 那么,很显然,“物理地址-逻辑地址”这样的一个映射关系,总归是需要一个数据结构去维护它的。
- 其映射的方式就是页表。页表里面的一项,就维护了
4KB
的物理內存的放置。
2.2 页表的设计
2.2.1 内部碎片的产生
- 每个页表的项都是
4KB
,它们的排列方式是紧密的,也就不存在外部碎片。 - 但是页表分配的单位是原子化的,即使空间的大小不足
4KB
,也会按照4KB
去做分配,因此会产生内部内存碎片。
2.2.2 按需引入的 Swap
策略
- 如果内存空间不足,和外部磁盘进行
Swap
的时候,不再和段式管理类似,将整个逻辑空间和外部进行交换。 - 程序在运行的时候,写到外部磁盘上面的只是几个页,不会占用过多的时间,因此,内存交换的效率比较高。
2.2.3 内存寻址方式
- 在分页机制下,虚拟地址分为两部分,页号和页内偏移。页号作为页表的索引,页表包含物理页每页所在物理内存的基地址,这个基地址与页内偏移的组合就形成了物理内存地址,见下图。
- 虚拟地址通过页号+页内偏移量组成,通过 页号 找到页表中对应的项,然后该项记录了物理页号,读取到物理页号之后,通过页内偏移量计算出实际的物理地址。
- 总结一下,对于一个内存地址转换,其实就是这样三个步骤:
- 把虚拟内存地址,切分成页号和偏移量;
- 根据页号,从页表里面,查询对应的物理页号;
- 直接拿物理页号,加上前面的偏移量,就得到了物理内存地址。
2.2.4 缺页中断
[[操作系统-缺页中断]]
2.2.5 多级页表:降低空间开销
2.2.5.1 单级页表的空间开销预估
- 操作系统为
32
位,页大小为4KB
,内存为4GB
- 所谓
32
位,就是内存虚拟地址是由32个bit组成的,这32
个bit
,需要存放页表号+偏移量。一般来说,单级页表需要20
个bit
去放置页表号。 - 物理内存一共
4GB
,用4KB
的原子化的块去映射,一共就是1024 * 1024
个块,差不多 一百万 个块,每个块需要一个表项,那么表项需要占用4
个字节(1024*1024=2^20
,20
个字节用来存放物理页表号,剩下的存放一些额外信息),那么,至少需要 4 * 100 万的空间存放页表,也就是 大约4MB
的空间专门用来放置页表。
2.2.5.2 多级页表如何解决空间
32bit
的内存地址当中,需要20bit
放置页表号,但是如果将页表拆成多级的,其映射如下图所示
- 粗略计算一下,映射
4GB
的内存空间,需要4KB
的一级页表空间,4MB
的二级页表空间。 - 看上去空间开销更大了。
- 但是,仅仅依靠
4KB
的一级页表,就可以覆盖全部的内存映射关系了,如果某个地址没有用到,就不必开二级页表去管理了,换言之,二级页表的空间开销是按需消费的。 - 比如物理内存用了
20%
,那么一级页表4KB
,加上4*0.2=0.8MB
大小的二级页表空间会被消费,那么,可以节约较多的空间。
2.2.5.3 64
位操作系统的4级页表
- 原理上和二级页表类似,只有全局页表目录需要加载,其他的页表目录都是按需引入的。
2.2.6 TLB
缓存加速
将常用的页表项放到一个更多的地方,那么,对于计算机而言,比内存还快的地方,就是
CPU
缓存了。TLB(Translation Lookaside Buffer)
又称快表,本质上就是常用页表项的 CPU缓存。有了 TLB 后,那么 CPU 在寻址时,会先查 TLB,如果没找到,才会继续查常规的页表。
TLB 的命中率其实是很高的,因为程序最常访问的页就那么几个。
3. 段页结合管理
3.1 优势
- 希望能够同时利用分段管理的逻辑性和分页管理的高效率。
- 便于后续的管理。降低成本的开销,同时提高了内存的利用率。
3.2 具体实现方式
- 先将程序划分为多个有逻辑意义的段,也就是前面提到的分段机制;
- 接着再把每个段划分为多个页,也就是对分段划分出来的连续空间,再划分固定大小的页;
- 地址结构就由段号、段内页号和页内位移三部分组成。
- 寻址方式如下:
- 先读取虚拟地址当中的段号,通过段号找到具体的段
- 在该段中,通过段内页号,找到具体的页
- 通过页内偏移量,找到实际的物理地址