本章了解操作系统是如何管理内存的。首先要知道计算机的体系结构和内存分层体系,才能了解计算机是怎么有效管理内存的。
1.计算机体系结构/内存分层体系
计算机体系结构
计算机体系结构主要包括三大部分
- CPU:主要完成对程序执行的一个控制。
- 内存:主要放置了代码以及相关的数据。
- I/O设备:比如硬盘、键盘、鼠标等都属于I/O设备,它们各自有不同的功能,来配合程序发挥更大的作用。
内存分层体系
计算机的内存层次可以看到从上到下包括很多个类别。第一个是寄存器,第二个是cache(缓存),这两部分都是位于CPU内部的,特点是速度快但是容量小,能放置的数据是有限的。
为此,在操作系统里面还有一块很大的数据叫做主存,或者叫物理内存。主存存放运行的程序,容量大,但是相较于前两者速度较慢。
主存里面可能放置了多个程序同时运行,有可能出现对内存需求比较大,就将内存中放不下的数据放到硬盘(外存)中去。利用操作系统的帮助,其实可以实现不用的数据暂时先放在硬盘上,等用到的时候再加载进内存,这样虽然慢一些,但可以满足内存的需求,这就是后面会提到的虚拟内存机制。当然内存的数据会在掉电后消失,也需要保存到外存。
这样来看,计算机内存层次呈“金字塔”结构。
操作系统在内存管理中的目标
操作系统在内存管理中有以下4个目标:
- 抽象:希望程序通过操作系统的帮助,可以不用太过关注底层的细节。它不用考虑物理内存在什么地方,不用考虑外设在什么地方,它只用访问一段操作系统告诉它的连续地址空间就可以了,我们把这段连续地址空间称为逻辑地址空间。
- 保护:程序在执行的过程中有可能去访问别的程序的地址空间,我们希望通过操作系统保护每个程序独立的地址空间,防止恶意程序的破坏。
- 共享:保护程序独立地址空间并不意味着完全隔离,不同的程序之间可能会有交互,那就需要操作系统提供一个共享地址空间,来使得程序之间能够安全、可靠地交互。
- 虚拟化:当在内存中放了很多程序之后,可能会出现内存不够的情况,通过虚拟内存的机制将最需要的数据放在内存中,将暂时不需要的数据放在外存中,通过这种方式可以有效地实现一个虚拟的更大的地址空间。如上图所示。
为了实现这些目标,操作系统采用了一下方法:
- 程序重定位
- 分段
- 分页
- 虚拟内存
- 按需分页虚拟内存
这些方法会在后面介绍。
2.地址空间&地址生成
在介绍操作系统管理内存的方法之前,先要了解什么是地址空间以及地址空间是怎么生成的。
地址空间定义
一般地址空间分为两种,物理地址空间和逻辑地址空间。
物理地址空间是硬件支持的地址空间,是实际落在硬盘和内存上的地址空间,而逻辑地址空间是在CPU运行时程序看到的一段地址空间。逻辑地址空间看起来是一段简单的一维地址,其实它只是为了方便用户程序而存在的,到了真正访问的时候还会通过一定的对应关系映射到实际的物理地址空间上去。如上图例子所示。
逻辑地址生成
逻辑地址是为了方便用户程序使用而存在的,那它是如何生成的呢?
程序看到的是一个符号的逻辑地址(变量),这个符号逻辑地址通过编译、汇编、链接、程序加载最终生成一个可以在内存中运行的逻辑地址,这一系列步骤不需要操作系统的帮助,借助应用程序、编译器以及加载器(loader)就可以完成。
物理地址生成
这个图可以看到,应用程序在访问一个指令的时候,这个指令所处的逻辑地址是如何对应到内存中的物理地址上。CPU取出指令执行时,需要知道指令的物理地址,CPU刚开始只知道指令的逻辑地址,需要查找逻辑地址和物理地址的映射关系。CPU中有个模块叫MMU(内存管理单元),MMU保存了这种映射关系的表,CPU可以查表完成映射。
整个映射流程可以描述成以下步骤:
- CPU执行指令,CPU中的ALU(计算逻辑单元)部件需要知道这条指令的内容,它带着逻辑地址这个参数发出映射请求。
- CPU中的MMU回去查找表中是否有对应的物理地址,如果没有,就去内存中找,如果找到的话,CPU控制器会对内存发出请求获取某一个物理地址的内容,这个内容其实就是指令的内容。
- 主存将物理地址的内容通过总线返回给CPU,CPU拿到内容后就能开始指令的执行。
这个流程里操作系统的作用在于提前把逻辑地址和物理地址的映射关系建立好。另一方面,操作系统也保证了程序访问的地址空间是合法、安全的。
MMU表中映射的map会告诉每个程序能够合法访问的地址空间,如果越界访问会被操作系统拒绝