内存(三) - Swap Page

  • 作者: 雪山肥鱼
  • 时间:20210308 22:28
  • 目的:Swap Page
# 1. 页的换入换出机制
  ## 1.1 Swap Space 交换空间
  ## 1.2 The Present Bit
  ## 1.3 Page Fault
  ## 1.4 何时发生swap out
# 2. 交换机制
  ## 2.1 Other VM policies
  ## 2.2 Trashing 概念 抖动
# 3.VAX/VMS 内存系统
  ## 3.1 内存管理硬件
  ## 3.2 VAX 页替换
  ## 3.3 影响后来者的 VM 内存管理技巧(demanding page & Cow)

1. 页的换入换出机制

放开最大的假设,物理内存可以装的下地址空间。实际上这是不可能的,所以OS将地址空间中不常用的内存,转移到硬盘中。

1.1 Swap Space - 交换空间

  • Swap Space 是定义在disk 上的一块空间,pages 可以在这里换入换出。
  • Swap Space 的单位是 page-united 的。
  • OS 需要记住这片空间的物理硬盘地址。
    举例:


    物理内存与交换空间.png

    每个进程所用到的page,并不全在物理内存中,其中不进场用的存放在硬盘的交换空间中。

1.2 The Present Bit

我们需要增加将page 换入换出的机制,换出暂且不提,这里先考虑换入的机制

  • 考虑page换入机制:也是取数据的流程
    a. CPU 给出一个地址,优先经过MMU计算VPN(仅过了多级页目录的计算)
    b. 去TLB中寻找,找到了,则与offset 进行组合,找到物理地址
    c. 没有在TLB中找到,通过MMU 找到page table所在位置,拿着VPN 去 page table 进行查找。
    d. 检查page table 中的 present bit 是否为1
    e. 为1,找到对应的PTE,提取其中的PFN,结合offset 得到真正的物理地址
    f. 为0,产生page fault,触发页交换机制
  • 为什么叫page fault 而不叫 page miss
    • fault的叫法有一定历史原因,也因为OS handle fault的一种机制
    • 当一些不正常的硬件问题发生时,硬件会将控制权转移给OS,希望OS能正确处理。
    • 比如,一个进程要访问的页并不在物理内存中,这种情况,硬件就只能报出一个异常,OS接管,所以这里叫做page fault,是从硬件角度出发的。

1.3 Page Fault

当page 不存在于物理内存,而被交换到了disk上,此时又有进程要访问这个page时,OS 需要将产生 swap page的操作去迎合 page fault 所产生的异常。

  • 问题1,OS 去硬盘的哪个位置寻找想要的page呢?
    在很多系统中,页表中的Page Table Entry, 页表项会存储对应的disk address. 当OS 收到page fault时,可以利用对应的PTE 去查找address,从而向disk 发出I/O 请求。
  • 问题2:硬件为什么不处理page fault
    a. 硬件 配合disk去处理 page fault 会非常的慢
    b. 能够处理page fault,硬件需要懂得swap space 的概念,并且知道如何向disk发出I/O 请求等一些列细节操作,会非常复杂。

当disk I/O请求结束,OS会更心page table, 将PTE 对应的 present 位设置位1,并更新 PFN,(已经更新到physical address 中了)。
其实也会出发TLB Miss,毕竟刚刚被swap in 到了 内存中。
对disk 产生I/O 申请 去查询page 所在disk中的位置时,进程时阻塞的,那么OS此时会去运行其他的进程,直到page fault 被解决。等待I/O的过程是昂贵的,索性去做其他事情

VPN = (VirtualAddress & VPN_MASK) >> SHIFT
(Sucess, TlbEntry) = TLB_Lookup(VPN)
if(Success == True)
    if(CanAccess(TlbEntry.ProtectionBits) == Ture)
        Offset = VirtualAddress & Offset_MASK
        PhyAddr = (TlbEntry.PFN<

Page falut Control Flow Algorithm(Software)

  PFN = FindFreePhysicalPage() //先看内存里有没有地方swap in
  If(PFN == -1)                              //没有将某些page踢出去
      PFN = EvictPage()
DiskRead(PTE.DiskAddr, PFN)   //在disk上寻找,并刷新PFN
PTE.present = True
PTE.PFN = PFN
RetryInstruction()                        // 重新执行指令

1.4 何时发生 swap out

当内存满了,再去进行 内存的交换,从而发生swap out 这是很不现实的。OS 必须保证一直有一部分内存是空闲的。

  • high watermark 高水位线
  • low watermark 低水位线

两者结合产声 evicting page.
其实主要用了page daemon 或者叫做 swap daemon 守护进程。
物理内存容量低于低水位线 -> evicting page
物理内存容量高于高水位线 -> 不做交换
现象:有的时候什么都不做,电脑磁盘会一直在转一直在响,那么就是在做paging的动作

2. 交换机制

page 的交换机制大部分都封装在OS中,程序员不用关心。
其实这一章节的主要内容就是对比各种交换机制的效率和优劣。
最终推荐使用的是 LRU,本质上用到了局部性原理
空间局部性:P 被访问了,那么P-1 P+1 都有可能被访问
时间局部性:最近被访问了,那么有很大概率会再次被访问
LRU: Least-Recently-Used:最近最少使用
LFU: Least-Frequently-Used:最低频率使用

LRU 也会借助硬件,记录一个 reference bit,结合reference bit 的 clock algorithm 可以实现LRU。

2.1 Other VM Policies

除了 page replacement,还会有其他策略,比如 page selection,中的 demand paging. 也就是说 OS 会做到 预测。比如说page P 被带到了内存中,被访问了,那么Page P+1 有可能被访问到,那么也会被带进内存。

OS如何将page 写进disk中:
page 的 clustering / group 写策略,抱团写,提高效率。

2.2 Trashing 概念 抖动

当活动的进程使用的内存超过了实际物理内存的大小,那么OS 会频繁的进行 paging 的操作,page的换入换出。比如大型游戏的多开,会出现硬盘一直在转的现象,paging 的导致的Trashing 现象。
这个时候OS的处理方式就是杀掉某些进程,减少进程工作集。linux的处理方式就是杀掉内存密集型的进程。

3 VAX/VMS 内存系统

让我们看下VAX/VMS 操作系统的虚拟内存管理

3.1 内存管理硬件

  • VAX为每个进程提供了一个32位的虚拟地址空间
  • page size 512个字节
  • 23 bit VPN + 9 bit offset. 高2位用于分页所在的段
  • 该系统是分页和分段的混合体
VAX/VMS Address Space.png
  • P0 和 P1 组成了 Progress Process.
  • S 是 system space。这一段是跨进程共享的。

VMS的问题很明显,就是page size 调小了,会导致现性的page table 很大,所以位P0 P1 每个区域分别提供了一个页表。所以 堆栈之间未使用的部分并没有分配任何内存。
base register 存储基地址 bounds register 存储界限寄存器,即页表的数量

  • 为什么空指针访问会导致段错误
int *p = NULL;
*p = 10

硬件试图在TLB中查找VPN(0),遇到TLB未命中。查询页表,并且发现VPN 0 的条目别标记为无效,因此,我们遇到无效的访问,将控制权交给OS,这可能会中止进程(在UNIX系统上,会向进程发出一个信号,让他们对这样的错误做出反应,但是如果信号未被捕获,则会中止进程)
所以0页存在的原因 也是为了检测null-pointer 访问提供支持

内核虚拟地址空间(S)是每个用户地址空间的一部分。在上下文切换时,操作系统改变p0和p1寄存器以指向即将运行的进程的适当页表,但是不会更改S基址和界限寄存器,并因此将相同 内核结构映射到每个用户地址空间。
原因:

  • 如果OS收到用户程序 write 递交的指针,很容易将数据从该指针处赋值到它自己的结构中。
    • 如果内核完全位于物理你内存中,那么将页表的交换切换到磁盘时非常困难的。
    • 如果内核被赋予了自己的Address Space,那么用户应用程序和内核之间移动数据会变得非常痛苦。
  • 所以内核几乎就像应用程序库一样,尽管是收到保护的

OS当然不想让应用程序读取OS的数据和代码。从硬件角度进行支持,对page 进行分级。OS的data 和 code 的保护等级一定会高于应用程序的等级。当然如果应用程序准备访问高等级的OS代码,那么一定会产生trap,并且OS会杀掉你这个有冒犯的进程

3.2 VAX的页替换

VAX的页表项包含:

  • 有效位
  • 保护字段
  • 脏位
  • OS使用的保留字段
  • PFN
  • no reference bit

3.2.1 分段的FIFO

VAM提出了 分段FIFO 替换策略

  • 每个进程都有一个可以保存在内存中的最大页数,Resident Set Size , RSS 驻留集大小。
  • 每个页都保存在FIFO列表中,当一个进程超过其RSS时,先入的页被驱逐。FIFO不需要硬件支持

纯粹的FIFO 性能并不友好。为了提高FIFO的性能,VMS引入了 二次机会列表。页在从内存中被踢出去之前被放在其中。具体说:

  • 全局的干净页空闲列表
  • 脏页列表
    当进程P超过其RSS时,将从其每个进程的FIFO中移除一个页。如果未被修改,将其放在未被修改列表的末尾。如果脏了(以呗修改)将其放在脏页列表的末尾。

分段的FIFO算法接近LRU

3.2.2 页聚集

为了让交换I/O更有效,VMS增加优化,通过 聚集 clustering,将大批量的页从全局脏页列表中分组到一起,一举写入磁盘。

3.3 其他机智的VM管理技巧

3.3.1 按需置零 - 有需求时才会申请

以堆为例:通常情况将一页内存添加到address space 中。

  • OS在物理内存找到页,,为了安全期间置零
  • 映射到Address Space
  • 这种实现有缺陷,特别是当申请了这页,但是没有用到!

利用按需置零方法,OS 在遇到内存申请请求时,其实做的事情并不多。
遇到内存申请时:

  • 在页表中标记这一项 PTE 是不可访问的,但是设置了不可访问的原因是demand-zero
  • 如果进程写或者读这一块内存,那么操作系统才会遇到trap
  • OS查看原因,原来是 demand zero 在这个时候才会去向physcial memory 申请内存

其实意识就是 malloc 了1G 内存,不会立刻给你,用到的时候再给你。

3.3.2 COW copy on write 读时共享 写 时复制

  • 使用背景: OS 将 A 的 地址空间中的一页,拷贝到B 的地址空间中
  • 并不是真的copy, 而是将这一页映射到进程B, 同时会将这页设置成 cow(其实是read only)属性
  • 如果两个进程都只是读这一页,那么OS没反应
  • 当其中一个进程 尝试去写这个进程,OS会遇到trap,发现这一页是cow, 此时复制这一页,包括这一页的所有数据。

Unix 系统中的fork()和 exec() 的配合使用,就是利用COW技术。替换了address space 的 代码段。

开发VAX/VMS DEC公司对后续操作系统的影响很大,包括DEC在当时也是如日中天,但是由于决策的问题,也终究推出了历史舞台。

你可能感兴趣的:(内存(三) - Swap Page)