局部性原理
计算机组成原理里我们可以知道cache掉入的数据都是连续的
我们可以看下面的例子,data创建的数组,因为我们要读入的是这个数组所以调入的是这一段内存的内容就大概率不会miss
但是我们要知道有些程序的代码被执行的几率是很小的,我们要让大概率被执行的代码引用的空间落入cache,其实科学家研究过,一个程序其实只有一部分局部代码在运行时会被访问,并非所有代码都需要被执行。
这个就叫做局部性原理
大部分程序都是满足此原理
时间局部性有些变量会被重复访问
空间局部性比如a[i]=b[i]
修改缓存的数据
这里叫做脏区,大家可以自行百度一下,这个是计组的基础,其实就是修改cache然后回写
swap space
其实就是磁盘与内存的缓存区域
这个缓存也是为了解决硬盘和内存运行速度不匹配的问题,且硬盘容量比内存要大得多
所以这个缓存区能解决硬盘速度太慢,内存条空间较小的问题,他们是互补(理论上内存无限大)
我们做一个总结
我们看图,越往左存储空间越小,速度越快,越往右存储空间越大,速度越满。右边的设备是左边设备的扩充,我们只需要把常用数据放入左边的设备。
这整个就是虚拟内存的结构
部分装入,虽然内存很小,但是互补之后,我们只需要把不常用的存在低速设备里,常用的放入高速设备里,这就理论上达到无限内存,我们编程就不用担心物理内存的限制。
demand paging
请求式页面调度
并非所有虚内存的空间都在内存中有物理位置(从硬盘掉入内存),因为逻辑上我们需要满足无限内存,但是如果访问到不常用的数据就需要从硬盘里调用数据
判断页表里的valid/invalid值是否有效
判断数据是否在内存驻留
如果数据没有驻留在内存就向硬盘去调度(需要查询硬盘里是否有该数据),最后整个过程叫做paging
如果没有驻留在内存就不会产生page fault,直接取内存驻留的数据,如果有page fault就需要从硬盘调用数据进入内存
上面整个请求调页对于虚拟内存来说可以扩大内存空间,但是这个机制是要访问内存和硬盘的所以调页时间肯定是要比正常时间要低很多
其实这里还有个问题,如果需要调页时发现内存空间满了,那么调页磁盘的空间无法进入内存空间,这里我们就需要解决这个问题
根据下面的图我们可以发现我们可以用置换来解决,也就是我们需要讲一块内存空间存入硬盘,然后再讲我们需要的硬盘数据存入内存,这个过程就叫做页面置换
但这里还有个问题,如果调页置换,我们需要考虑刚置换的内存数据,会否等下又要置换回来,如果多次这样时很浪费运行周期的。
这里我们讨论一些算法
fifo算法先进先出
我们将最先进入内存空间的数据置换
因为这个数据再内存中待的最久,所以一般都已执行完了
我们举个例子,这个例子里我们可以看到3 0和2 3这里再0和3刚被淘汰下次执行又页面置换了,后面几次调用又好几个都是这样
我们可以看到除了前三个强制页面置换,一共发生了十二次页面置换
最优算法
我们可以看到这个算法产生的置换更少,因为它是根据后面需要的资源去判断谁需要被置换
而且既然它叫做最优了,那么基本就是目前最优了
但这里有个致命缺陷,导致整个算法无法实现,我们前面就提到过,我们无法预测程序下一步需要什么
那么我们优化整个算法尽量逼近这个算法的实现逻辑,我们无法判断后面进程需要什么资源,那么我们就只能根据前面执行过的来判断
LRU算法
比fifo算法少了三次,比最优算法多了三次。
系统的抖动
在页面置换时请求调出去的内存可能下一步指令有需要调用,所以这里会产生大量的反复调用调出的动作,这个动作就叫做抖动
这里最后一句说了抖动还有一个特性,就是置换的时间远远大于调用此进程的时间,这个就叫做抖动。
抖动的原因
页框分配太少
并发进程过多(这里其实也是进程过多页框过少)