有了页表的支持,我们可以使得不同用户态运行程序的内存空间之间无法访问,达到隔离和保护的作用。但页表如何仅仅只支持这个功能就太大材小用了。我们其实还可以通过页表实现更多的功能:
-
内存共享:把两个虚拟地址空间通过页表映射到同一物理地址空间。这只需通过设置不同索引的页表项的内容一致即可。
-
提供超过物理内存大小的虚拟内存空间:这一步需要结合异常中断处理和硬盘来完成。其基本思想是在内存中放置最常用的一些数据,不常用的数据会被放到硬盘上,但给用户态的软件一种感觉,觉得这些数据都在内存中。当用户态软件访问到的数据不在内存中(暂时存放在硬盘上)的时候,这条访存指令会引发异常中断,由操作系统的异常中断处理例程进行管理。这时操作系统会分析引发异常的内存地址,能够把对应缓存在硬盘中的数据重新读入这个内存地址,并让用户态软件重新执行产生访存异常的那条指令。这些由操作系统完成的工作在用户态完全“看”不到。从用户态软件的角度看,只是操作系统给用户提供了一个超出实际物理内存大小的虚拟内存空间。
-
按需分配内存:用户态软件在运行时要求操作系统提供很大的内存,操作系统“表面上”表示满足用户需求,但在背后并没有实际分配对应的物理内存空间。等到用户态软件实际执行到对这些内存的访问时,由于没有分配对应的物理内存空间,会导致产生访存异常。操作系统的异常中断处理例程发觉这是用户态软件以前确实要求过的内存空间,则在从系统管理的空闲空间中分配一页或几页物理内存给用户态软件,并让用户态软件重新执行产生访存异常的那条指令。这些由操作系统完成的工作在用户态也完全“看”不到。但从操作系统的整体管理的角度看,这种方式在用户态软件确实需要的时候把内存分配给用户态软件,提高了内存的使用率,避免了用户态软件“圈地不用”的现象。
为了高效地完成上述三件事情,操作系统需要考虑应该把哪些不常用的内存换出到硬盘上去,这就是内存的页替换算法,常见的有LRU算法,Clock算法,二次机会法等。而在实现上,由于涉及异常处理和硬盘管理等,虚存管理在整个ucore实现中的相对复杂度是最大的。