虚拟内存

  • 1. 虚拟内存的起因(缓解内存不足)
  • 2. 覆盖技术(80年代90年代初)
  • 3. 交换技术
  • 覆盖与交换
  • 4. 虚拟内存管理技术(虚存技术)
  • 程序的局部性原理
  • 基本概念
  • 基本特征
  • 虚拟页式内存管理
  • 介绍
  • 页表表项
  • 缺页情况
  • 缺页处理
  • 后备存储
  • 虚拟内存性能
  • 5. 页面置换算法
  • 5.1 功能和目标
  • 5.2 最优页面置换算法
  • 5.3 先进先出算法(FIFO)
  • 5.4 最近最久未使用算法(Least Recently Used,LRU)
  • 5.5 时钟页面置换算法
  • 5.6 二次机会法
  • 5.7 最不常用法(Least Frequently Used,LFU)
  • 5.8 Belady现象、LRU、FIFO、Clock的比较
  • Belady现象
  • LRU、FIFO、Clock的比较
  • 6 全局页面置换算法
  • 6.1 局部页替换算法的问题、工作集模型
  • 工作集模型
  • 1 工作集(working-set)
  • 2 常驻集
  • 6.2 两个全局置换算法
  • 6.2.1 工作集页置换算法
  • 6.2.2 缺页率页面置换算法
  • 6.2.3 抖动问题



1. 虚拟内存的起因(缓解内存不足)

内存越来越不够用,程序规模的增长速度远大于存储器容量的增长速度

overlay2里的文件修改 需要重启容器吗_工作集

registers(寄存器):把更小更快的存储器放在离CPU近的地方,使CPU更快访问到

Cache:由于内存相对寄存器速度较慢,所以在中间加一个cache,缓存内存数据,使得CPU取数据尽量从cache取,而不需要每次都访问主存,保证速度快

把寄存器和Cache容量做大不太切实际

内存现在越来越大,然而软件也越来越大

硬盘速度太慢,不能把程序放在这执行,考虑将硬盘容量用上。希望操作系统能帮助程序员利用这些硬盘空间,从而得到一个更大更快的虚拟空间。为了有效管理物理内存,出席拿了分页分段机制,希望能在分页分段之上解决容量不够的问题

overlay2里的文件修改 需要重启容器吗_换出_02


现有的物理内存掉电数据就丢失了

希望充分的,利用硬盘,把不常用的代码数据放到硬盘,常用的代码数据放到内存,虚拟出大内存的感觉,需要硬件、CPU、MMU、操作系统的内核协同在一起,

overlay2里的文件修改 需要重启容器吗_换出_03

overlay:最开始,内存很小,需要程序员手动写代码,把一些常用的数据保存到内存,不常用的放到硬盘
swapping:后来,由os把不用的数据导出到硬盘,开销大,要把一整个程序导出和导入
虚拟内存技术:把程序中的一部分数据导出,基于分段分页+os管理实现虚存

2. 覆盖技术(80年代90年代初)

操作系统能力很弱,代表是dos系统,硬件只有640k的内存,小内存却要运行大程序

程序员自己实现数据的换入换出

overlay2里的文件修改 需要重启容器吗_换出_04

原理:将程序根据执行逻辑进行分类,划分为若干个区间(相对独立的模块)。不能同时运行的模块设置其为共享空间,按时间模式依次执行(分时),要设置常驻内存空间,负责管理何时将相应的函数数据调入内存调出内存,不常用的数据在其他程序执行时要放到外存,用到的时候调入内存

overlay2里的文件修改 需要重启容器吗_操作系统_05

A调用B、调用C

  1. A先调用B,所以B从硬盘调入内存,
  2. 此时,A又调用C,则把B使用的空间释放掉,把C从硬盘调入内存;
  3. C调用E,则把E从硬盘调入内存,C调用E的时候B和F不会被执行,因为是串行,所以B和F不会被放到内存中
  4. E执行完后,C会调用F,所以会把E占用的内存空间释放掉,把F从硬盘导到内存中去,使得F可以正常执行

粒度以程序的逻辑调用关系来实现

逻辑调用关系不止一种覆盖方法:

overlay2里的文件修改 需要重启容器吗_操作系统_06

overlay2里的文件修改 需要重启容器吗_换出_07

缺点(开销):

  1. 程序员设计的开销(把大的程序分成几个小的功能模块,如何找到最佳的覆盖方法使得占用空间最小)
  2. 数据的换入换出(时间换空间)

3. 交换技术

linux使用的一种方法

操作系统帮助完成,当多个程序再跑的时候,使用操作系统来管理这些程序合适换入换出内存

overlay2里的文件修改 需要重启容器吗_工作集_08

不用的程序且内存不够就把它换出去(写入外存),用的时候再换回来
粒度:一个程序

overlay2里的文件修改 需要重启容器吗_操作系统_09

overlay2里的文件修改 需要重启容器吗_操作系统_10

问题:

  • 什么时候交换?内存不够时才作此操作
  • 交换区大小?要够那个程序运行
  • 程序换出后再换入位置不一样了?(重定位)若换入后还是以前的位置,继续执行;若不是原来的位置了,就采用动态地址映射(页表,动态表变化的,虚地址与实地址的映射关系是动态变化的)

覆盖与交换

overlay2里的文件修改 需要重启容器吗_换出_11

覆盖

交换

覆盖发生在一个程序里,使一个程序中的多个没有调用关系的模块共享一个内存区域

交换是在程序间

覆盖由程序员手动指定逻辑关系

交换由操作系统内部完成

粒度是模块

粒度是程序,开销比较大

4. 虚拟内存管理技术(虚存技术)

overlay2里的文件修改 需要重启容器吗_缺页_12

overlay2里的文件修改 需要重启容器吗_操作系统_13

为解决覆盖和交换存在的问题,提出了虚存技术
目标:集2个优点于一身

  • 和覆盖一样,内存中存的不是整个程序,但此操作由os来完成
  • 和交换一样,对其进行换入换入换出,但粒度小

对于P3,不是所有的数据都放在了内存

程序的局部性原理

overlay2里的文件修改 需要重启容器吗_换出_14

指程序在执行时呈现出局部性原理,即在一段时间内,整个程序的执行仅限于程序中的某一部分。相应的,执行所访问的存储空间也局限于某个内存区域。
局部性原理又表现为:时间局部性和空间局部性。

  • 时间局部原理是指如果程序中的某条指令一旦被执行,则不久后该指令可能再次被执行;如果某数据被访问,则不久后该数据可能再次被访问。
  • 空间局部性是指一旦程序访问了某个存储单元,则不久后,其附近的存储单元也将被访问。
    (更详细的见https://www.jianshu.com/p/5c9b28c95c64)
    如果能实现程序的局部性原理,就可以高效的完成虚存技术

overlay2里的文件修改 需要重启容器吗_工作集_15

一个int整型在32位os占4Byte
A[1024][1024]占用102410244=4M
但物理内存只有4K

数组在内存中是按行存储的

overlay2里的文件修改 需要重启容器吗_缺页_16

一页为4K,而a0,0到a0,1023占210 *4=4K
一页正好是数组的一行
解法1将先将a0,0-a0,1023调入,访问完a0,0后,访问a1,0,需要再次调入a1,0-a1,1023,产生缺页,开销很大

基本概念

overlay2里的文件修改 需要重启容器吗_缺页_17

把程序的一小部分放入内存中,如果要访问的指令或数据不在内存中,就把它从硬盘中调入,如果内存足够大,直接调入,如果内存不够大,则由os来选择一个以后不会或较少用到的部分调出内存

基本特征

overlay2里的文件修改 需要重启容器吗_操作系统_18

  • 空间大:物理内存和硬盘的一部分相加得虚拟空间
  • 部分交换:换出的是段或页,不是换整个程序,分段和分页是由操作系统管理的
  • 不连续:物理内存分配得不连续,虚拟地址空间使用的不连续(不连续体现在本来所有的都应该连续的放在虚拟内存空间中,但是某些数据或代码会被换出去,所以会不连续。但操作系统会帮我们弥补好,使得程序能够正常的被访问)

虚拟页式内存管理

介绍

overlay2里的文件修改 需要重启容器吗_换出_19


查找页表,如果存在位为0的话,虚拟内存空间对应的物理空间是没有的,就会发生访问异常,这个访问异常就是虚拟内存管理的有效手段

  • 大部分采用页式存储管理,还要增加请求调页和页面置换功能
  • 基本思路
  • 请求调页:只装入部分页,访问到不在内存的页时,请求调页,CPU向操作系统发出缺页异常,根据缺页的信息找出相应的页,调到物理内存中去
  • 页面置换:内存不够时调入调出

overlay2里的文件修改 需要重启容器吗_换出_20


需要换进来页时,把哪些页换出去对效率很重要

页表表项

overlay2里的文件修改 需要重启容器吗_缺页_21

为实现调换和置换,增加几个位

  • 驻留位:该页在内存还是外存
  • 保护位:能否访问该页
  • 修改位:该页是否被写过。如果被写过,说明与放在硬盘得数据是不一致的,在做换入换出时,要写回;若没被写过,则直接释放该页
  • 访问位:当前页是否被经常访问,若不是经常访问(0),则可以换出

缺页情况

overlay2里的文件修改 需要重启容器吗_操作系统_22


X标识驻留位为0,数字表示驻留位为1

左面是页表

MOV REG,0 //8192

把虚拟的0地址赋给寄存器,页表里0对应的是2,2一个页的大小即24K=2*4096=8192,所以物理地址位8192

overlay2里的文件修改 需要重启容器吗_换出_23

MOV REG ,32780 //缺页中断

即页表项第8项 32K-36K(32780/1024=32.011),该项是X,所以是缺页

overlay2里的文件修改 需要重启容器吗_操作系统_24

缺页处理

overlay2里的文件修改 需要重启容器吗_操作系统_25

若CPU执行一个指令,若内存地址无对应的映射关系,则缺页异常,os来处理,看内存中是否有空闲空间,

  1. 若有,则分配一个物理页帧,转到第4步,把该物理内存以页的单位转入到分配的物理页帧那,然后修改页表,把存在位(驻留位?)置为1,重新执行指令
  2. 空闲空间没有了,则要采取页置换算法

后备存储

overlay2里的文件修改 需要重启容器吗_操作系统_26

  • 数据文件,如一个数组会以文件的形式放在硬盘上的,访问若没有,则从硬盘中把这个数据文件读出来,放到硬盘的文件上叫做后备存储
  • 代码,每一条指令也是数据,放在硬盘,把执行代码作为数据读入内存,进一步执行。访问某条指令不存在时,就会从执行程序中把它读到内存来
  • 库文件:需要才从硬件读出来
  • 程序在运行过程中会产生数据,这些数据占空间且需要换出到硬盘,硬盘直接开辟一个空间(swap file)
    以上保证了空间有效性

虚拟内存性能

取决于缺页次数及硬盘读写开销

overlay2里的文件修改 需要重启容器吗_工作集_27

p——缺页概率
q——对页需要写回的概率
EAT=10(1-p)+5,000,000p(1+q)
(1+q):写回还要占时间
p足够小,则是EAT接近10,若程序具有局部性原理,产生缺页的次数就会很少,则效率很高,则会接近10

5. 页面置换算法

overlay2里的文件修改 需要重启容器吗_换出_28

5.1 功能和目标

overlay2里的文件修改 需要重启容器吗_缺页_29

功能:当缺页中断发生时,需调入新的页面而内存已满时,选择内存当中哪个物理页面被置换
目标:尽可能地减少页面换进换出次数(即缺页中断的次数),因为硬盘读写速度慢,所以要尽量减少次数

常驻内存要进行页面锁定

overlay2里的文件修改 需要重启容器吗_工作集_30

overlay2里的文件修改 需要重启容器吗_工作集_31

因为找的时候如果那一个也都不存在了,也就不需要再看偏移量了,所以就只需要考虑页即可
不太可能做到不缺也,只能缺页概率减少

5.2 最优页面置换算法

根据将来这个程序将来会访问哪个页来设计

很难实现

但可以把算法算作最佳的评算标准,越逼近则越好

overlay2里的文件修改 需要重启容器吗_工作集_32


分配4个物理页帧,当访问第5个页时就需要置换:

  1. 0时刻时,假设abcd就已经在内存中了,1-4时刻都命中了,不会产生缺页中断
  2. 5时刻时,需要置换

    要选离当前时刻距离最远的来做替换

overlay2里的文件修改 需要重启容器吗_换出_33

5.3 先进先出算法(FIFO)

overlay2里的文件修改 需要重启容器吗_工作集_34

驻留最久的就被换出
使用一个链表,链表头部是驻留时间最久的页面,尾部插入的是驻留时间最短的。新页添加在链表尾部,同时删除头部
缺点:

  1. 性能差。产生缺页次数比较多
  2. Belady现象。给的物理页帧,产生缺页次数越多的现象

overlay2里的文件修改 需要重启容器吗_换出_35


0时刻,假设安装abcd的顺序,所以5时刻时驻留时间最长的是a

overlay2里的文件修改 需要重启容器吗_缺页_36


实现简单,但产生的缺页次数较多

5.4 最近最久未使用算法(Least Recently Used,LRU)

overlay2里的文件修改 需要重启容器吗_缺页_37

选择过去最久未使用的页面,根据过去来推测未来,最优是根据未来推测未来

overlay2里的文件修改 需要重启容器吗_缺页_38

overlay2里的文件修改 需要重启容器吗_操作系统_39


效果虽好,但开销很大

overlay2里的文件修改 需要重启容器吗_换出_40

5.5 时钟页面置换算法

Clock 页面置换算法,LRU的近似,对FIFO的一种改进

访问位,若访问则置1,由硬件完成

overlay2里的文件修改 需要重启容器吗_工作集_41

把各个页面组织成环形链表(放在物理内存),若访问位为1,则不是个老页,指针下移,若访问位为0,则是老页,就可以把它换了

是否是老页,依据是访问位,定期会把访问位置0

overlay2里的文件修改 需要重启容器吗_缺页_42


依据used bit(右边数第2位)

当前指向Page 0: 1 1 4,访问位为1,说明最近被访问过,此时需把访问位置0,再把指针顺时针下移到Page 3:1 1 1,一直找到访问位为0的,即找到Page1,所以把Page1 的页表项换掉

overlay2里的文件修改 需要重启容器吗_工作集_43

命中指针不移动

与LRU缺页次数差不多,达不到,但很接近
注意:当访问位为1时,将访问位置为0并下移指针
访问:读和写都是访问

5.6 二次机会法

使用used bit和dirty bit

overlay2里的文件修改 需要重启容器吗_缺页_44

脏位:写操作则置为1,由硬件设置

若进行读操作,则内存和硬盘的数据一致,无需写回

若进行写操作,则内存和硬盘的数据不一致,需写回

提出二次机会法(Enhanced Clock algorithm),同时利用脏位和访问位来决定那页可以置换,以减少写回

上图右下角为替换规则,如2位均为0,则该页可以替换,如分别为0,1,则把脏位设为0,指针下移

如2位均为1,则变为0,1,指针下移,当指针再次回到该页时,变为0,0(这里体现了2次机会)经常使用的dirty位会更少的换出

overlay2里的文件修改 需要重启容器吗_缺页_45


带上标的为对其进行写操作

time=5:

  • a:1,1->a:0,1
  • b:1,1->b:0,1
  • c:1,0->c:0,0
  • d:1,0->d:0,0
  • a:0,1->a:0,0
  • b:0,1->b:0,0
  • c:0,0->e:1,0(替换)

time=9:
指针指向00 d,直接替换为10 e

接近LRU,优先换出只读的页,使得读写硬盘的次数减少

5.7 最不常用法(Least Frequently Used,LFU)

访问次数最少,则换出

overlay2里的文件修改 需要重启容器吗_工作集_46

简单的使用计数器的弊端:

  1. 如果把计数器用一个寄存器来存,则硬件开销很大
  2. 如果对计数器进行查找,要查找链表,访问也很大,链表很长,就会早场访问时间过长

LRU和LFU的区别:

  • LRU考察的是多久未访问,时间越短越好
  • LFU考察的是访问的次数或频度,访问次数越多越好(问题:一个页面在进程开始时使用得较多,但以后就不使用了,实现也很费力,解决方法:没有考虑时间,如可以 定期将次数寄存器右移一位,即次数除以2)

问题:

overlay2里的文件修改 需要重启容器吗_工作集_47

overlay2里的文件修改 需要重启容器吗_换出_48

(这个???)

time

Requests

0

a->8

b->5

c->6

d->2

1

c

a->8

b->5

c->7

d->2

2

a

a->9

b->5

c->7

d->2

3

d

a->9

b->5

c->7

d->3

4

b

a->9

b->6

c->7

d->3

5

e

a->9

b->6

c->7

e->1

为什么不是替换d?定期除2?

5.8 Belady现象、LRU、FIFO、Clock的比较

Belady现象

overlay2里的文件修改 需要重启容器吗_工作集_49


Belady现象:在采用FIFO算法时,有时会出现分配的物理页面数增加,缺页率反而提高的异常现象

原因:并没有考虑到程序运行的动态性

  • 分配物理页数为3

    只有3次访问命中
  • 分配物理页数为4

    只有2次命中
  • LRU不会产生这个问题(符合栈算法,未展开讲)

LRU、FIFO、Clock的比较

overlay2里的文件修改 需要重启容器吗_操作系统_50

如果程序本身没有局部性特征,则LRU可能会退化为FIFO(LRU和FIFO和Clock会变得差不多)

Clock算法使用一个访问位

overlay2里的文件修改 需要重启容器吗_操作系统_51

6 全局页面置换算法

6.1 局部页替换算法的问题、工作集模型

overlay2里的文件修改 需要重启容器吗_操作系统_52

由上图可知,当分配3个物理页帧时,9个缺页,当分配4个物理页帧时,1个缺页数,物理页帧数目会对缺页数有影响
当对一个程序分配的物理页帧数目相同时,限制了程序产生缺页的特点,因为程序在运行过程中有阶段性,可能一开始需要很多内存,中间很少,最后又很多,对于物理页帧的需求是动态变化的。
之前都是假设分配的物理页帧的个数是固定的,假定os只能跑一个程序,那么就可以分配给它所有的物理页帧。但是如果不是只跑1个程序,如果给每个程序分配的物理页帧数固定,则这样是不灵活的,能不能根据程序运行的阶段动态分配物理页帧,是全局页面置换算法要考虑的问题

工作集模型

overlay2里的文件修改 需要重启容器吗_缺页_53

1 工作集(working-set)

工作集:一个进程当前正在使用逻辑页面集合 当前正在使用:是一个时间段,起始时间和它的一个持续长度,代表当前

逻辑页面集合:存了该程序这段时间内访问的页面

overlay2里的文件修改 需要重启容器吗_缺页_54

t:当前执行时刻 Δ:一个长度,一个定长的页面访问的时间窗口

t+Δ=1个时间段

t会变,而Δ不会变,w会变

overlay2里的文件修改 需要重启容器吗_工作集_55

t2那个局部性较好

t1那个有的部分局部性较好,有一定的局部性,如访问了4次7,而整体局部性不如t2

overlay2里的文件修改 需要重启容器吗_工作集_56

2 常驻集

常驻集:指当前时刻,进程实际驻留在内存当中的页面集合

overlay2里的文件修改 需要重启容器吗_工作集_57


常驻集 VS 工作集:

  1. 常驻集:当前运行的程序需要访问的页哪些在内存中
  2. 工作集:当前运行的程序需要访问的页是哪些,这些页可能在内存中,有可能不在,我们希望所访问的页都在内存中,一旦不在内存中就会产生缺页中断

不是分配给程序越多的物理页帧越好,当此程序运行时,有多余的物理页帧可以动态分配给其他程序,会降低缺页率。
给不同的程序分配不同的常驻集,缺页次数变少,性能提升,这样操作,局部页面算法是无法解决的

6.2 两个全局置换算法

6.2.1 工作集页置换算法

替换不在工作集里的页

随时间推移,不属于工作集的也会被扔掉

overlay2里的文件修改 需要重启容器吗_换出_58


随着程序的执行,只要这个页不属于工作集窗口了,就可以把这个页丢掉

假如,上图的窗口大小为4

时刻

工作集

0

{a,d,e}

1

{a,c,d,e}

中断

2

{a,c,d}

t=-2:e,t=-1:d,t=0:a,t=1:c,t=2:c而窗口大小为4,所以e就不在工作集里了

3

{a,c,d}

4

{b,c,d}

t:0:超出工作集窗口

{}

与局部替换算法的区别:
当前在物理内存中放哪些页,取决于它是否在工作集窗口之内,超出工作集窗口的页面都会被换出去,所以可以确保物理内存中始终有足够的页存在,可以给其他程序提供足够的内存,从而减少页面置换的次数,使整个系统多个程序缺页次数降低

overlay2里的文件修改 需要重启容器吗_工作集_59

6.2.2 缺页率页面置换算法

窗口大小也可以变

使常驻集大小可变,一种更灵活的全局算法

依据是缺页的频度,缺页次数多,则分配更多的物理页;缺页次数少,则分配的物理页够多,则可以压缩常驻集

overlay2里的文件修改 需要重启容器吗_操作系统_60

overlay2里的文件修改 需要重启容器吗_换出_61

overlay2里的文件修改 需要重启容器吗_操作系统_62

overlay2里的文件修改 需要重启容器吗_工作集_63

(当前产生中断的时刻-上一次产生中断的时刻)与 T的大小

overlay2里的文件修改 需要重启容器吗_工作集_64


overlay2里的文件修改 需要重启容器吗_操作系统_65


overlay2里的文件修改 需要重启容器吗_换出_66


tcurrent-tlast=这次产生缺页中断的时间t-上一次产生缺页中断的时间t

如t=4时,产生缺页中断,而上一次产生缺页的t=1,所以tcurrent-tlast=4-1=3

工作集的是得每一次都要判断是否超出工作集
而缺页的是只有在中断时才考虑
这2个都是动态调整,而局部的是只有分配的物理页帧满了的时候才调整

6.2.3 抖动问题

overlay2里的文件修改 需要重启容器吗_操作系统_67

工作集代表着本身对内存访问的固有属性
常驻集是os当前把程序运行需要的页面放到内存

overlay2里的文件修改 需要重启容器吗_操作系统_68


涉及到2个参数:

  • 平均缺页时间(MTBF)
  • 内存大小

红线:随着程序运行的越来越多,内存很快就用完了,就会产生很多缺页,也就需要大量的换入换出,使得操作系统把大量的时间都用在了换入换出上,所有的CPU时间都被操作系统用来换入换出了,从而导致整个系统的效率降低

需要找到最优点,使得跑的程序尽可能的多,同时系统利用率很高

overlay2里的文件修改 需要重启容器吗_缺页_69

同时还需要平均缺页时间(MTBF)与页缺失服务时间(PFST)尽量相等,比值越大说明缺页频度越低。

overlay2里的文件修改 需要重启容器吗_工作集_70

随着跑的程序越来越多,缺页中断发生的越来越频繁,即MTBF越来越小,而PFST不变,所以MTBF/PFST会越来越小
找到NI/O-balance 跑的程序很多,缺页数较少,系统利用率也可以保持较高的利用率

希望通过os的管理,使得系统利用率很高,系统中跑的程序也比较多,达到系统资源的充分利用

总结:
局部算法和全局算法与程序访问内存的访问序列有联系,和os分配给这个程序的页帧大小也有关。虚存需要这些算法来实现有效的缓解内存不够的现象,同时还要保证系统高效的运行