本文是对操作系统概念(第七版)——虚拟内存的学习总结,不足之处,欢迎批评指正。
1、虚拟内存的理解:
先将部分程序导入内存,执行完成后导入下一部分程序,给我们的感觉是内存变大了,实际上物理内存的大小并未发生变化。
虚拟内存的优点:
(1)将逻辑内存和物理内存分开。
(2)虚拟内存允许文件和内存通过共享页而为两个或多个进程所共享。
2、按需调页
按需调页:顾名思义,在需要时才调入相应的页。
支持按需调页的硬件:
(1)页表:该表能够通过有效-无效为或保护位的特定值,将条目设为无效。
(2)次级存储器(交换空间,通常为快速磁盘)
3、写时复制
这种技术允许父进程与子进程开始时共享共享同一个页面,这些页面被标记为为写时复制页,即如果任何一个进程需要对页进行写操作,那么就创建一个共享页的副本。
4、页面置换(重要)
页置换采用如下方法:如果没有空闲帧,那么就查找当前没有使用的帧,将其释放。
(1)查找所需页在磁盘上的位置
(2)查找一个空闲帧
a,如果有空闲帧,那么就使用它,
b,如果没有,使用页置换算法选择一个牺牲帧
c,将牺牲帧的内容写到磁盘上,改变页表和帧表
(3)将所需页读入空闲帧,改变页表和帧表
(4)重新启动程序。
常见的页置换算法
(I)FIFO页置换
最先进入的页被置换。
需要注意的是FIFO页置换会有一种特殊现象——Belady异常:对有的页置换算法,页错误率可能随着所分配的帧数的增加而增加。FIFO可能就出现这种现象。
(II)最优页置换opt
置换最长时间不会使用的页,即能预知将来的情况。但是将来的情况我们无法预知,因此这种算法难以实现。
(III)LRU页置换(最近最少使用算法least-recently-used algorithm)
FIFO使用的是页调入内存的时间,OPT使用的是将来的时间。
LRU置换为每个页关联上上一次使用的时间,当必须置换一页时,LRU选择最长时间没有使用的页。
最优置换和LRU置换都没有Belady算法(证明略)
(IIII)近似LRU页置换
页表中的每一项都关联一个引用位,每当引用一个页时,相应的位就被置位。因此我们虽然不知道引用顺序,但是我们知道哪些页被引用,哪些未被引用。近似LRU算法又有一下三种方法:
(a)附加引用位算法
通过在规定时间间隔里记录引用位。
0000000,11111111,上述两个字节分别表示在8个周期内从未被引用和一直被引用的情况。因此值最小,就是应该置换的页。
(b)二次机会算法
这种算法只有引用位本身,没有历史位,因此只有一位。当要选择一个页时,检查引用位,如为0,直接置换,如为1,则给该页二次机会,同时清0,寻找下一个0位置,所以而二次机会算法的基本算法是FIFO算法。
(c)增强型二次机会算法
通过将引用为和修改位作为一对有序位来考虑。
(0,0)——最近未使用且未修改过
(0,1)——最近未使用但修改过
(1,0)——最近使用但为修改过
(1,1)——使用且修改过
(IIIII)基于计数器的页置换
为每一个页保留一个用于记录其引用次数的计数器,因而可以形成以下两种方案:
最不经常使用页置换算法(LFU)——置换出引用次数最小的页
最常使用页置换算法(MFU)——认为最小次数的页可能刚刚调入,且还没有使用。
(IIIIII)页缓冲算法
系统保留一个空闲帧缓冲池,当出现页错误时,会选择牺牲帧,但是牺牲帧写出之前,所需要的页就从缓冲池中读到空闲内存。这样加速了重启。
5、帧分配
研究问题:如何在各个进程之间分配一定的空闲内存?
由于性能原因,必须有足够的帧来容纳所有单个指令所引用的页,因此有一个帧的最小数量的限制。帧的最小数量是有计算机体系结构决定的,而最大数量是由物理内存决定的。
(1)分配算法
平均分配,比例分配(比例可以根据进程大小或者优先级等来计算)
(2)全局分配和局部分配
全局分配:允许一个进程从所有帧集合中选择一个置换帧
局部分配:每个进程只能从自己的分配帧中选择置换。
6、系统颠簸
频繁的页调度操作
原因:当多道程序的程度增加到一定时,会引起颠簸
7.内核内存的分配
内核内存分配的特殊性:
(1)内核需要为不同大小的数据结构分配内存,因此必须谨慎分配内存。
(2)有的硬件需要直接和物理内存打交道,因此需要内存常驻在连续的物理页中。
以上两个特殊性是的内核内存的分配通常是从空闲池中获取,,而不是从内存链表中获取。
常见的内核内存分配有两种方法:
(i)Buddy系统分配
内存按2的幂的大小进行分配,如果请求大小大于当前2的幂内存,那么调整到下一个2的幂。
(II)slab分配
slab是由一个或多个物理上连续的页组成。高速缓冲cache含有一个或者多个slab,每个内核数据结构都含有一个cache,每个cache含有内核数据结构的对象实例。
优点:
(1)没有因碎片引起的内存浪费。因为每个数据结构都有一个cache,每个cache都有若干个slab组成,而每个slab又分为若干个和对象大小相同的部分。
(2)内存请求可以快速满足。
操作系统中的内存管理技术是十分复杂的。现在的操作系统基本都使用逻辑地址和物理地址这两个概念。简单来说,逻辑地址就可以理解为虚拟地址,这个地址是让用户,也就是我们使用者看的,这个地址是虚拟的,并不真实存在,但是经过硬件和软件的配合,将逻辑地址映射到硬件中实实在在的物理地址上,实现了逻辑地址和物理地址的分离。
当系统执行一个程序或者说开启一个进程并执行它的时候,一般都需要将进程的所有信息都加载到内存中,然后才能让CPU执行,因为内存是直接与CPU交互的,在通常的计算机中,内存就像我们所说的1G、2G、4G、8G等,目前大家使用的多数都是4G左右的内存,这样的内存看起来并不是很小,但是与我们的计算机上的硬盘相比较就十分渺小了,现在我们使用的硬盘一般都在512G以上,很多都使用1T的硬盘,所以这样看来,我们的计算机的内存是十分重要的,也需要谨慎使用。通常大家在使用电脑的时候,都会开启很多程序, 比如说:挂着QQ、听着歌、看着网页等等,这些程序的执行都可以看做一个个进程,这些进程的执行在原始情况下都需要将所有的进程数据和代码等信息都放到内存中才能执行,而这么多程序同时放到内存中,有时候会使得内存满载,导致内存不够用,更甚至于,大家平常玩的大型游戏,例如使命召唤等,可能一个程序所需要的内存容量就大于计算机本身的内存容量,那么这个程序就肯定不能执行了。
鉴于上述的很多原因,现在的计算机系统基本上都使用了虚拟内存技术,但是需要注意的是,虚拟内存技术确实带来了很多好处,但是这一技术实现起来需要硬件和软件的协调,所以难度比较大。那么什么是虚拟内存呢?刚刚提到过,很多内存管理策略都需要同时将多个进程放在内存中,以便执行这些进程,这些策略都需要在进程执行之前将整个进程放在内存中。而虚拟内存技术允许执行进程不必完全放在内存中,这样我们就可以运行比物理内存大的程序,使得程序员不受内存存储的限制。
写过完善的程序的程序员都会有一个感触,就是一个项目的程序虽然非常多,但是其实有一部分程序并不经常执行,或者基本上没有执行过,比如说异常处理、错误处理等,那么这些程序使得我们可以只需要加载需要执行的部分,从而减少了内存使用。
从而,我们可以构造一个大的虚拟内存空间,然后将其映射到较小的物理内存。这个大的虚拟内存空间存储我们进程的所有信息,而当执行进程时,我们只加载需要执行的部分,需要什么再加载什么。这里就需要采用一定的技术,比如按需调页、页面置换、帧分配等,使得进程的执行可以在虚拟内存和物理内存之间进行协调,完成整个程序的执行。
总的来说,虚拟内存技术主要有以下优点:虚拟内存可以大于物理内存,一般为物理内存的1.5倍到3倍,从而可以运行比物理内存大的程序,进而使得更多的程序可以同时执行,提高了多道程序的程度,增加了CPU的使用率,并且使得进程之间的独立性得到了更好的体现。
下面简单说下内存的基本管理,通常将逻辑内存进行分页,类似于切蛋糕,将一块大的蛋糕切成很多小块,分页是同样的道理,将逻辑内存分成很多小的页面,然后通过页表,映射到物理内存,而物理内存则划分为很多成为帧的块,从而和页对应起来,页面和帧的对应关系主要是通过页表来保存的,页表中有很多条目,较为详细地保存了这些信息。一般进程都有自己的内存空间,这里可以说有自己的虚拟内存空间,上面所说的虚拟内存技术就是指进程的虚拟内存空间存储了所有的进程信息,然后虚拟内存空间分成很多页,这些页并不是在进程执行时全部换入到物理内存,而是按照需要进行换入,需要哪一页就换入哪一页,这需要一定的算法管理,这里就不再详述。至于十分具体的虚拟内存管理方式和算法大家可以阅读《操作系统概念》一书,上面讲解的十分清楚。