OS——从虚拟内存扯到页面置换算法

文章目录

    • 虚拟内存
        • 为什么需要虚拟内存
        • 虚拟内存的好处
    • 段页式存储
      • 用户角度
      • 计算机角度
    • 缺页中断
    • 缺页异常的处理过程
    • 页面置换算法
      • 先进先出( FIFO)
      • 最近最久未使用(LRU)
      • 最佳置换算法( OPT)(实际上无法实现)
      • LRU的模拟实现原理

虚拟内存

为什么需要虚拟内存

  • 物理内存小,效率低我们的物理内存是有限的,当有多个进程要执行的候,一个进程分配[4G][]内存,物理内存很快就 用完了;没有分配到资源的额进程智能等待,这样效率很低;
  • 指令直接访问内存,不安全指令都是直接访问内存的,所有数据放在物理内存时,进程间就可以修改数据,甚至会修改内核空间的数据;
  • 运行地址不对由于内存是随机分配的,所以运行地址也是不正确的;

虚拟内存的好处

  • 虚拟内存会让每个进程都觉得自己有4G独立空间,实际上用多少内存,就会对应多少物理内存.
  • 进程的虚拟空间是相互独立的,进程之间互补干扰.
  • 程序运行时,[MMU]通过固定的虚拟地址去查询页表(查询页表是很慢的,因此有[TLB][]缓存记录相应的物理地址,每个进程的页表是独立的,一个页表一个[TLB][]).

那我们程序需要访问的逻辑地址如何访问到真实的内存空间呢?在这里只提及段页式存储机制

段页式存储


用户角度

​ 对用户而言,分段是对内存的有效使用;当用户发出一个逻辑地址,用户希望访问到特定程序段的内存空间。


计算机角度

​ 对于计算机而言,分页可以提高内存的使用效率。操作系统需要满足两个方面的需求,则希望用户发出的逻辑可以通过[MMU][]转换成页框号和页内偏移量,从而直接去访问真实的内存空间。所以就采取了段页相结合的方式来管理内存。


​ 用户发出访问程序段的逻辑地址**<段号,段内偏移量>,通过对这一逻辑地址的运算将其转换为访问页的虚拟地址<页号,页内偏移量>,再由MMU将其转换为内存的物理地址<页框号,页内偏移量>。**通过这种方式,用户访问的就是虚拟内存,经过两次地址映射后,变成真实的物理地址。

OS——从虚拟内存扯到页面置换算法_第1张图片

图片来源于网络

缺页中断

[MMU][]收到进程传来的虚拟地址,通过虚拟地址去查询物理地址的时候( 只翻译页号,偏移量一样的 ),就会先去看页表,如果发现没有相应的物理地址,就会发生缺页异常。

缺页异常的处理过程

操作系统立即阻塞该进程,并将磁盘里对应的页映射在内存中,然后使该进程就绪,如果内存已经满了,没有空地方了,那就找一个页覆盖,至于具体覆盖的哪个页,就需要看操作系统的页面置换算法是怎么设计的了.

页面置换算法

此处笔者自然想到三种类型的线程(轮询线程,段任务优先线程和先来先执行线程)

先进先出( FIFO)

原理:把内存中驻留时间最久的页面给予覆盖(移除内存);

  • 优点:先进先出算法实现简单,是最直观的一个算法
  • 缺点:先进先出的性能最差,因为与通常页面的使用规则不符合,所以实际应用少

最近最久未使用(LRU)

原理:选择最近且最久未被使用的页面进行移出;

  • 优点:由于考虑程序访问的时间局部性,一般能有较好的性能;实际应用多。
  • 缺点:实现需要较多的硬件支持,会增加硬件成本。

最佳置换算法( OPT)(实际上无法实现)

原理:每次选择未来长时间不被访问的或者以后永不使用的页面进行淘汰。

  • 优点:最佳置换算法可以保证获得最低的缺页率。
  • 缺点: 最佳置换算法是一种理想化算法,具有较好的性能,但是实际上无法实现(无法预知一个进程中的若干页面哪一个最长时间不被访问)。

LRU的模拟实现原理

1.基于链表+Hash表/
Hash表+双向链表
链表增删时间复杂度 O(1) Hash表查询时间复杂度O(1)


思路比较简单,两个方法,set()和get()基于哈希表和双向链表。先通过哈希表查找缓存块的位置,也就是缓存块在链表中的位置。然后把该缓存块置于链表表头。如果缓存已经满了,那就把表尾的缓存块丢掉,再在表头插入新的缓存块。


之所以要用双向链表是因为只需要记录尾指针,查找,删除或插入尾节点的时间为O(1),单向链表为O(N),单链表只有后继指针,没有前驱指针,而双向链表包含前驱指针,故删除指针后,可直接将前驱结点和后继结点连起来

你可能感兴趣的:(虚拟内存)