光了解Page的基本原理还不够,还需要知道如何设计存储才能达到一个更好的性能。
页式存储管理
工作集模型
在虚拟页存储管理中,当一个进程被启动,其所有页面都还在外存。当CPU取第一条指令时,就会引发缺页中断。因此,在程序启动一开始,很容易发生缺页中断,工作一段时间后再维持稳定,如图所示:
这种工作方式被称为demand paging
:页面不是预先被装入内存,而是根据需要随时调整。
访存的局部性与工作集
- 访存的局部性(locality):在进程运行的任何阶段,它都只访问它的页面中较小的一部分
- 工作集(working set):一个进程当前使用的页的集合
- 抖动:分配给进程的物理页面数太小,无法包含其工作集,频繁地在内存和外存间换页
- 工作集模型:页式存储管理系统跟踪进程的工作集,并保证在进程运行以前它的工作集就已经在内存中了。在进程运行之前预先装入页面也叫做预先调页(prepaging)。
分配策略
当发生缺页时,页面置换算法作用的范围不同,对应不同的分配策略:
- 局部页面置换算法:在进程所分配的页面范围内选取将被置换的页面
- 每个进程分配固定大小的内存空间
- 全局页面置换算法:在内存中所有的页面范围内选取被置换的页面
- 所有进程动态共享系统的物理页面,分配给每个进程的页面数动态变化
一般来说,全局算法的性能更好。这是因为在进程运行期间,工作集可能发生较大的变化;而局部算法可能浪费空间,也更容易造成抖动。
物理页面的分配
那么,如何来分配不同进程的物理页面呢?
在全局算法下,当一个进程刚开始运行时,可以先根据进程的大小给它分配一定数量的物理页面,然后在进程的运行过程中,再动态调整内存空间的大小。
可以采用缺页率(Page Fault Frequently)算法:
- 缺页率:一秒钟内出现的缺页数(统计)
- 定义进程缺页率的上下界,使得进程的缺页率在其范围之内
- 负载控制(load control):系统内运行的进程过多,无法使所有进程的缺页率都低于A,则需要将一些进程换出至外存,这里的交换是为了减少潜在的内存需求
- 这种算法的前提假设是:当分配给进程的物理页面增多时,缺页率将会下降。
页面大小
页面大小需要权衡多方互相矛盾的因素:
- 内碎片、空间利用率
- 从统计的规律看,内碎片的大小一般是半个页面;页面越小、内碎片也会越小、浪费越少
- 例,内存被分配n段,页面大小为p, 则总内碎片大小为np/2
- 页表项数、页表装入时间
- 同一程序,页面大小越小,需要的页表项会越多
- 传送不同大小页面所花的时间相差不多,同一程序,页面越小、页面数会越多、故时间会越长
一般来说,页面大小为512字节到4KB之间。
虚拟存储接口
通常虚拟存储器对进程和程序员是透明的,即所能看到的全部是在一个带有较小的物理存储器之上一个大的虚地址空间
允许程序员对内存映射进行某些控制,可以实现两个或多个进程共享同一段内存空间,即页面共享
- 可用来实现高性能消息传递系统
分布式共享存储器
- 允许在网络上的多个进程共享一组页面,这些页面可以组成一个共享的线性地址空间
段式存储管理
页式管理是把内存视为一维线性空间;而段式管理是把内存视为二维空间。
很多时候,拥有两个或多个独立的虚拟地址空间可能要比单个空间好得多。
将程序的地址空间划分为若干个段(segment),程序加载时,分配其所需的所有段(内存分区),这些段不必连续;物理内存的管理采用动态分区。
程序通过分段(segmentation)划分为多个模块,如代码段、数据段、共享段。
- 可以分别编写和编译
- 可以针对不同类型的段采取不同的保护
- 可以按段为单位来进行共享,包括通过动态链接进行代码共享
优点
- 没有内碎片。
- 便于改变进程占用空间的大小。
- 易于实现代码和数据共享,如共享库
引入新的问题
- 存在外碎片,需要通过内存紧缩来消除。
与页式存储系统的不同:页面是定长的而段不是。
当进行段调度时,可能会出现很多的外碎片(external fragmentation)
参考资料
- Operating System:Design and Implementation,Third Edition
- Linux 内存映射函数 mmap()函数详解