虚拟内存在逻辑上实现了对内存容量的扩充,既满足了用户的需要,又改善了系统性能。这篇文章总结了虚拟内存的基本概念、实现方式以及几种页面置换算法。最后是几种文件分配方式。
基本概念
局部性原理:程序执行时,在一较短时间内,程序的执行仅仅局限于某一部分,其访问的存储空间也局限于某个区域。主要表现在两个方面:
- 时间局限性:如果某条指令被执行,不久以后该指令可能再次执行;如果某些数据被访问,不久以后该数据可能再次被访问;
- 空间局限性:如果某段存储单元被访问,其附近的存储单 元可能也会被访问。
基于局部性原理,在加载程序时,只需将当前执行所需的部分页面或段装入内存。程序执行时,如果要访问的页面或段不在内存中,则发生缺页中断,于是 OS
利用请求调页功能将相应的页面或段调入内存,继续执行。如果内存已满,则利用置换功能,将内存中暂时不用的页面或段调出到外存,再将所需的页面或段调入内存,使程序继续执行。
虚拟内存是指具有请求调入功能和置换功能,从逻辑上对内存容量进行扩充的一种内存系统。实现方式有三种:请求分页存储管理方式、请求段式存储管理方式和请求段页式存储管理方式。
请求分页存储管理
请求分页存储管理是在分页存储管理的基础上,增加请求调页和页面置换功能。它允许用户程序只装入部分页面就启动程序运行。在运行中如果发现所需页面不在内存中,则发出缺页中断,OS
就会将外存中相应的页面调入内存使其继续运行。每次调入和换出的基本单位是长度固定的页面。
请求分页存储管理中的地址转换与分页式相比,在页表项中添加了一些标志位:
- 状态位:表示该页是否已调入内存。
- 修改位:表示该页在调入内存后是否被修改过。在置换该页时,判断是否要把它写回外存。
- 访问位:表示该页在一段时间内被访问的次数。供置换算法在选择换出页面时参考。
- 外存地址:表示该页在外存上的地址。
请求分页存储管理系统中,在进行地址转换时,首先在快表中查找要访问的页。如果找到,便修改页表项中的访问位,供置换算法选择换出页面时参考。如果是写指令,还需要将修改位置为 1
,表示该页在调入内存后被修改过。然后利用页表项中的物理块号和页内地址,得到物理地址。
如果在快表中未找到该页的页表项,则应到内存中去查找页表,再从找到的页表项中的状态位来判断该页是否调入内存。如果该页已调入,则应将该页的页表项写入快表;如果该页没有调入内存,则应该产生缺页中断,操作系统从外存中找到缺失的页面。
如果内存已满,则利用置换算法选择一页换出,如果该页被修改过,则需要将该页写回到外存中。最后将缺页从外存换入到内存中,继续运行程序。
页面置换算法
最优算法(Optimal)
置换在未来最长时间内不再被访问的页面。这只是一种理想情况,只能用来评价其他置换算法的性能。
先进先出算法(FIFO)
选择进入内存时间最长的页面进行置换。在实现时维护一个所有已调入内存的页面的链表,按照进入内存的先后次序排序,链首最早,链尾最进。在出现缺页时,选择链首的页面进行置换,将新页面添加到链尾。
这种算法实现简单。但调出的页面可能会经常访问,性能较差,一般和其他算法结合使用。
最近最久未使用算法(LRU)
选择最长时间没有使用的页面进行置换。它依据的是如果某个页面长时间没有被访问,则在将来一段时间可能还不会访问。
在实现时维护一个按最近一次访问时间排序的链表,链表首是刚使用过的页面,链表尾是最久未使用的页面。在访问页面时,找到相应的页面,将其移动到链表首;在出现缺页时,删除链表尾节点,将新页面添加到链表首。
这种算法是最优算法的一种近似,但实现起来仍然比较复杂。
时钟算法(Clock)
也称为最近未使用算法(NRU
)。在实现时,在页表项中增加一个访问位,表示过去一段时间内是否被访问过,初始时都置为 0
,另外将页面组织成环形链表,添加一条指针指向最先被调入内存的页面。
当访问某页面时,将其访问项置为 1
。在出现缺页异常时,从指针处开始查找,如果页面没有被访问过,即访问项为 0
,则进行置换;如果被访问过,则将访问项置为 0
,暂不换出,再将指针指向下一个页面继续查找,直到找到可以置换的页面。
最少使用算法(LFU)
置换最近一段时间访问次数最少的页面。在实现时,对每个页面设置一个访问计数,在访问页面时,对访问计数加 1
;在出现缺页异常时,置换访问计数最少的页面。
文件分配
文件分配实际上是如何表示分配给一个文件的数据块的位置和顺序。主要有以下几种分配方式:连续分配、链式分配和索引分配。
连续分配
使用连续的若干个数据块来存储文件。它在文件控制块中记录起始第一个数据块的位置和长度。
采用连续分配方式,读取文件的顺序访问和随机访问效率较高,但是剩余的碎片难以利用,另外文件长度增长也比较复杂。
链式分配
将文件以数据块链表的形式存储。文件控制块中包含了第一个数据块和最后一个数据块的指针。
链式分配方式在创建、增大、缩小文件时比较容易,而且没有碎片,但是不能实现真正的随机访问,另外一个数据块被破坏,后面的数据块就都丢了。
索引分配
为每个文件创建一个索引数据块,索引数据块中存储了指向文件数据块的指针列表,文件控制块中包含了指向索引数据块的指针。
这种实现在创建文件、增大、缩小文件时比较容易,也没有碎片,也支持随机访问。但是在文件很小时,存储索引开销相对较大,在文件很大时,需要增加额外的索引快。
UFS(Unix File System)
UFS 的多级索引分配:在文件控制块中,如果数据块小于 10
,采用直接索引;如果大于 10
块,第 11
块开始采用一级间接索引,它先指向一个索引块,索引块中再指向实际的数据块。如果数据块大到一定程度,会采用二级间接索引,依次类推。
多级索引分配方式大大提高了文件大小的限制阈值,可以动态分配数据块,文件扩展很容易,对于小文件开销较小,对于大文件使用间接索引也比较合理。