背景
研究发现在很多情况下并不需要将整个程序放到内存中。
- 程序通常有处理异常错误条件的代码,由于这些错误很少发生,所以这些代码几乎不执行。
- 数组、链表和表通常分配了比实际所需要的更多的内存。
- 程序的某些选项或功能可能很少使用。
虚拟内存(virtual memory)将用户逻辑内存和物理内存分开。这在现有物理内存有限的情况下,为程序员提供了巨大的虚拟内存。
除了将逻辑内存与物理内存分开,虚拟内存也允许文件和内存通过共享页而为两个或者多个进程所共享,这样带来了如下的优点:
- 通过将共享对象映射到虚拟空间地址,系统库可为多个进程所共享。
- 虚拟内存允许进程共享内存。
- 虚拟内存可允许在用系统调用fork()创建进程期间共享页,加快进程创建。
按需调页
一个执行程序从磁盘载入内存的时候有两种方法。
- 选择在程序执行时,将整个程序载入到内存中。
- 另一种选择是在需要时才调入相应的页,这种技术称为按需调页(demand paging)。
按需调页系统类似于使用交换的分页系统,交换程序是对整个进程进行操作,而调页程序只是对进程的单个页进行操作。
基本概念
当换入进程时,调页程序推测在该进程再次换出之前使用到的哪些页,仅仅把需要的页调入内存。从而减少交换时间和所需的物理内存空间。
这种方案需要硬件支持区分哪些页在内存,哪些在磁盘。采用有效/无效位来表示。当页表中,一个条目的该位为有效时,表示该页合法且在内存中;反之,相关的页无效(不在进程的逻辑地址空间内),或者有效但是在磁盘上。
对标记为无效的访问会产生页错误陷阱,这种陷阱是由于操作系统未能将所需的页调入内存引起的。处理这种页错误的方式:
- 检查进程的内部页表,以确定该引用是合法还是非法的地址访问。
- 如果引用非法,那么终止进程。如果引用有效但是尚未调入页面,那么现在应调入。
- 找到一个空闲帧。(从空闲帧链表中选取一个)
- 调度一个磁盘操作,以便将所需要的页调入刚分配的帧。
- 当磁盘读操作完成后,修改进程的内部表和页表,以表示该页已在内存中。
- 重新开始因陷阱而中断的指令。进程现在能访问所需的页,就好像它似乎总在内存中。
按需调页的性能
内存访问时间ma,p为页错误的概率
有效访问时间=(1-p)×ma+ p×页错误时间
内存访问时间为200ns,平均页错误处理时间为8ms
有效访问时间=(1-p)×200+p×8ms =(1-p)×200+p×8000000 =200+7999800p
写时拷贝
传统上,fork()为子进程创建一个父进程地址空间的副本,复制属于父进程的页。然而,由于许多子进程在创建之后会马上执行系统调用exec(),所以父进程地址空间的复制可能没有必要。
因此,可以使用写时拷贝的技术,这种方法允许父进程与子进程开始时共享同一页面。
这些页面标记为写时复制页,即如果任何一个进程需要对页进行写操作,那么创建一个共享页的副本。
当一个页要采用写时拷贝,从哪里分配空闲页:
- 许多系统提供了空闲缓冲池
- 按需填零技术,按需填零页在需要分配之前先填零,清除以前的内容
页面置换
需要页置换的情况
基本页置换
基本页置换
- 查找所需页在磁盘上的位置
- 查找一个空闲帧
a. 如果找到空闲帧,那么就使用它
b. 如果没有空闲帧,那么就使用页置换算法选择一个牺牲帧。
c. 将牺牲帧的内容写到磁盘上,改变页表和帧表 - 将所需页读入空闲帧,改变页表和帧表
- 重启用户进程
如果没有帧空闲,那么需要采用两个页传输(一个换入,一个换出),这种情况把页错误处理时间加倍了,页增加了有效访问时间。
FIFO页置换
Belady异常:页错误率可能随着所分配的帧数的增加而增加
最优置换(OPT或MIN)
置换最长时间不会使用的页
向后看,最后出现的数被替换
最优算法难以实现,主要用于比较研究。
LRU页置换(最近最少使用)
置换最长时间没有使用的页
向前看,最后出现的数被替换