交换技术已经使用了很多年。第一个Unix系统内核就监控空闲内存的数量。当空闲内存数量小于一个固定的极限值时,就执行换出操作。换出操作包括把进程的整个地址空间拷贝到磁盘上。反之,当调度算法选择出一个进程运行时,整个进程又被从磁盘中交换进来
现代的Unix(包括Linux)内核已经摒弃了这种方法,主要是因为当进行换入换出时,上下文切换的代价相当高。在Linux中,交换的单位是页面而不是进程。尽管交换的单位是页面,但交换还是要付出一定的代价,尤其是时间的代价。实际上,在操作系统中,时间和空间是一对矛盾,常常需要在二者之间作出平衡,有时需要以空间换时间,有时需要以时间换空间,页面交换就是典型的以时间换空间。这里要说明的是,页面交换是不得已而为之,例如在时间要求比较紧急的实时系统中,是不宜采用页面交换机制的,因为它使程序的执行在时间上有了较大的不确定性。因此,Linux给用户提供了一种选择,可以通过命令或系统调用开启或关闭交换机制。
在页面交换中,页面置换算法是影响交换性能的关键性指标,其复杂性主要与换出有关。具体说来,必须考虑四个主要问题:
· 哪种页面要换出
· 如何在交换区中存放页面
· 如何选择被交换出的页面
· 何时执行页面换出操作
请注意,我们在这里所提到的页或页面指的是其中存放的数据,因此,所谓页面的换入换出实际上是指页面中数据的换入换出。
1.哪种页面被换出
实际上,交换的最终目的是页面的回收。并非内存中的所有页面都是可以交换出去的。事实上,只有与用户空间建立了映射关系的物理页面才会被换出去,而内核空间中内核所占的页面则常驻内存。我们下面对用户空间中的页面和内核空间中的页面给出进一步的分类讨论。
可以把用户空间中的页面按其内容和性质分为以下几种:
(1) 进程映像所占的页面,包括进程的代码段、数据段、堆栈段以及动态分配的“存储堆”(参见图6.13)。
(2) 通过系统调用mmap()把文件的内容映射到用户空间
(3) 进程间共享内存区
对于第1种情况,进程的代码段数据段所占的内存页面可以被换入换出,但堆栈所占的页面一般不被换出,因为这样可以简化内核的设计。
对于第2种情况,这些页面所使用的交换区就是被映射的文件本身。
对于第3种情况,其页面的换入换出比较复杂。
与此相对照,映射到内核空间中的页面都不会被换出。具体来说,内核代码和内核中的全局量所占的内存页面既不需要分配(启动时被装入),也不会被释放,这部分空间是静态的。(相比之下,进程的代码段和全局量都在用户空间,所占的内存页面都是动态的,使用前要经过分配,最后都会被释放,中途可能被换出而回收后另行分配)
除此之外,内核在执行过程中使用的页面要经过动态分配,但永驻内存,此类页面根据其内容和性质可以分为两类:
(1) 内核调用kmalloc()或vmalloc()为内核中临时使用的数据结构而分配的页于是立即释放。但是,由于一个页面中存放有多个同种类型的数据结构,所以要到整个页面都空闲时才把该页面释放。
(2)