type
status
date
slug
summary
tags
category
icon
password
Property
Apr 15, 2023 03:23 PM
早期系统
从内存看,早期操作系统没有提供多少抽象给用户。基本上,机器的物理内存看起来如下图所示。
操作系统曾经是一组函数(实际上是一个库),在内存中(在本例中,从物理地址 0 开始),然后有一个正在运行的程序(进 程),目前在物理内存中(在本例中,从物理地址 64KB 开始), 并使用剩余的内存。这里几乎没有抽象。
多道程序和时分共享
过了一段时间,由于机器昂贵,人们开始更有效地共享机器。因此,多道程序(multiprogramming)系统时代开启,其中多个进程在给定时间准备运行,比如当有一个进程在等待 I/O 操作的时候,操作系统会切换这些进程,这样增加了 CPU 的有效利用率(utilization)。那时候,
效率
(efficiency)的提高尤其重要,因为每台机器的成本是数十万美元甚至数百万美元。但很快,人们开始对机器要求更多,分时系统的时代诞生了。许多人意识到批量计算的局限性,程序员们厌倦了长时间的(因此也是低效率的)编程—调试循环。
交互性
(interactivity)变得很重要,因为许多用户可能同时在使用机器,每个人都在等待(或希望)他们执行的任务及时响应。一种实现时分共享的方法,是让一个进程单独占用全部内存运行一小段时间,然后停止它,并将它所有的状态信息保存在
磁盘
上(包含所有的物理内存),加载其他进程的状态信息,再运行一段时间,这就实现了某种比较粗糙的机器共享。遗憾的是,这种方法有一个问题:太慢了,特别是当内存增长的时候。虽然保存和恢复寄存器级的状态信息(程序计数器、通用寄存器等)相对较快,但将全部的内存信息保存到磁盘就太慢了。因此,在进程切换的时候,我们仍然将进程信息放在内存中,这样操作系统可以更有效率地实现时分共享(见图 13.2)。
在图 13.2 中,有 3 个进程(A、B、C),每个进程拥有从512KB 物理内存中切出来给它们的一小部分内存。假定只有一个 CPU,操作系统
选择运行
其中一个进程(比如 A),同时其他进程(B 和 C)则在队列中等待运行。随着时分共享变得更流行,人们对操作系统又有了新的要求。特别是多个程序同时驻留在内存中,使
保护
(protection)成为重要问题。人们不希望一个进程可以读取其他进程的内存,更别说修了。地址空间
操作系统需要提供一个易用(easy to use)的物理内存抽象。这个抽象叫作地址空间(address space),是运行的程序看到的系统中的内存。理解这个基本的操作系统内存抽象,是了解内存虚拟化的关键。
个进程的地址空间包含运行的程序的所有
内存状态
。比如:程序的代码(code,指令)必须在内存中,因此它们在地址空间里。当程序在运行的时候,利用栈(stack)来保存当前的函数调用信息,分配空间给局部变量,传递参数和函数返回值。最后,堆(heap)用于管理动态分配的、用户管理的内存。程序代码位于地址空间的顶部(在本例中从 0 开始,并且装入到地址空间的前 1KB)。
代码是静态的(因此很容易放在内存),所以可以将它放在地址空间的顶部,我们知道程序运行时不再需要新的空间。
在程序运行时,地址空间有两个区域可能增长(或者收缩)。它们就是堆(在顶部)和栈(在底部)。把它们放在那里,是因为它们都希望能够增长。通过将它们放在地址空间的两端,我们可以允许这样的增长:它们只需要在相反的方向增长。因此堆在代码(1KB)之下开始并向下增长(当用户通过 malloc()请求更多内存时),栈从 16KB 开始并向上增长(当用户进行程序调用)。然而,堆栈和堆的这种放置方法只是一种约定,如果你愿意,可以用不同的方式安排地址空间 [稍后我们会看到,当多个线程(threads)在地址空间中共存时,就没有像这样分配空间的好办法了]。
目标
透明(transparency)
操作系统实现虚拟内存的方式,应该让运行的程序看不见。因此,程序不应该感知到内存被虚拟化的事实,相反,程序的行为就好像它拥有自己的私有物理内存。在幕后,操作系统(和硬件)完成了
所有的工作,让不同的工作复用内存,从而实现这个假象。
效率(efficiency)
操作系统应该追求虚拟化尽可能高效(efficient),包括时间上(即不会使程序运行得更慢)和空间上(即不需要太多额外的内存来支持虚拟化)。在实现高效率虚拟化时,操作系统将不得不依靠硬件支持,包括 TLB 这样的硬件功能。
保护(protection)。
操作系统应确保进程受到保护,不会受其他进程影响,操作系统本身也不会受进程影响。当一个进程执行加载、存储或指令提取时,它不应该以任何方式访问或影响任何其他进程或操作系统本身的内存内容(即在它的地址空间之外的任何内容)。因此,保护让我们能够在进程之间提供隔离(isolation)的特性,每个进程都应该在自己的独立环境中运行,避免其他出错或恶意进程的影响。
小结
- 操作系统的一个重要子系统:虚拟内存。
- 虚拟内存系统负责为程序提供一个巨大的、稀疏的、私有的地址空间的假象,其中保存了程序的所有指令和数据。
- 操作系统在专门硬件的帮助下,通过每一个虚拟内存的索引,将其转换为物理地址,物理内存根 据获得的物理地址但获取所需的信息。
- 操作系统会同时对许多进程执行此操作,并且确保程序之间互相不会受到影响,也不会影响操作系统。整个方法需要大量的机制(很多底层机制)和一些关键的策略。
参考
- 作者:GJJ
- 链接:https://blog.gaojj.cn/article/blog-09
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。