
操作系统入门(五) 内存篇之地址重定位、逻辑空间、物理空间以及程序如何装入内存
前面几节内容介绍了进程的构成、状态转换、进程间关系以及操作系统如何对进程调度。接下来我们将分三节内容介绍内存的相关知识,内容包括内存空间概述、操作系统如何为进程分配内存、内存物理地址与逻辑地址之间的转换、段页式存储、虚拟内存技术和页面置换算法等。
本节先介绍内存的基本情况、内存的逻辑空间和物理空间、程序如何装入内存以及内存的扩充技术。
操作系统内存知识体系大纲

01 内存与程序装入
- 内存是个啥
内存是CPU能直接存取 指令和数据的存储器,本质是被分割为一个个以字或者字节为存储单元的存储空间
,每个存储单元都有自己的地址,通过地址读写内存的数据。
CPU和IO系统都会直接与内存打交道。 程序也要载入到内存之后才能运行。
- 存储单元
如果计算机按字节编址,则单个字节就是一个存储单元,每个字节都有一个地址;
如果计算机按字编址(字长可能为16位或32位不等),则单个字就是一个存储单元,每个字都有一个地址;
- 内存管理梗概
在介绍操作系统功能的时候,我们知道内存管理是OS的功能之一。那么OS的内存管理具体又包含哪些事情?
1.内存分配与回收;
2.逻辑上对内存空间进行扩展,包括覆盖技术、交换技术 和 虚拟内存;
3.地址转换,将程序的逻辑地址转为物理地址,又称为重定位;
4.内存保护,保证各个进程的内存地址不越位,内存空间互不干扰。
- 进程的装入
我们知道程序存储在外存(如磁盘)的时候还只是一堆代码,是无法运行。程序只有进入内存变成进程之后才能接受操作系统的调度并运行。
那么程序装入内存前发生了什么事情呢?主要是编译、链接和装入这3件事。

编译:编译程序将高级语言翻译为机器指令,得到若干个目标模块;
链接:链接程序将编译后得到的目标模块以及所需库函数组合成一个完整的装入模块。
装入:装入程序将装入模块装入到内存中。
在编译阶段,程序不太可能知道数据将来会在物理内存的哪个地址,因此操作系统会为每一个程序定义一个属于该进程本身的逻辑空间,该逻辑空间只存储该进程的
代码和数据。逻辑空间内的每个字节对应一个逻辑地址,逻辑空间的地址是从0开始的。编译生成的指令和数据的内存地址也都是逻辑地址而非物理地址。
将程序装入内存之后,每个指令和对应的数据才有自己的物理内存地址,因此将 程序的逻辑地址转为物理地址是装入程序应该关注的事情 。
- 重定位
将程序的逻辑地址转为物理地址的过程称为重定位。重定位按照时机分为绝对重定位、静态重定位和动态重定位3种。
绝对重定位
是指编译时编译程序就决定好程序会放在内存的哪个位置,由编译程序产生具有绝对地址的机器指令,装入程序再按绝对地址将程序和数据装入内存。在绝对重定位下,装入模块的逻辑地址与物理地址完全一致。
绝对装入只适合于单道程序环境,内存中只会有一个用户程序,因此想放在哪就放在哪。
静态重定位
是指编译和链接后的装入模块的地址是相对地址,装入程序根据装入模块装入内存的开始位置对程序中的所有指令和数据的逻辑地址修改为物理地址。地址重定位是在装入内存时
一次性 完成的。
下图描述了静态重定位的逻辑地址与物理地址的转换。

静态重定位具有如下缺点:
1.静态重定位要求程序装入内存时就要操作系统为程序分配所有所需的内存空间,并且运行期间不能移动程序在内存中的位置,也不能再次申请内存空间。
2.程序的存储空间只能是连续的一片区域,不利于内存空间有效使用。
动态重定位
又称动态运行时装入,即编译和链接后装入模块的地址仍然是相对地址,装入内存时也不会立刻将逻辑地址转为物理地址,而是把地址转换推迟到指令执行时进行。
动态重定位需要硬件实现,所需硬件包括一对寄存器:
1.存放用户程序在内存的起始物理地址,称为基址寄存器;
2.存放用户程序逻辑地址的最大范围,称为限长寄存器。
运行指令时将指令内数据的 相对地址+基址寄存器的值 就能得到数据的物理地址。

动态重定位的好处如下:
采用动态重定位时允许程序(数据段和代码段)在内存中发生移动。
程序可以离散存储在内存,减少内存碎片。
程序运行可以只装入部分代码,节省运行进程时占用的物理内存。
程序可以动态申请内存,例如随着程序的运行,产生了越来越多的数据导致原本分配给该进程的内存不够用了,可以再申请更多内存。
后面介绍的 段式存储和页式存储都是动态重定位 。
- 链接
链接是将多个编译后的目标模块和用到的库函数合并为一个整体的可执行文件,也就是上面内容中所说的装入模块。链接的方式分为静态链接、装入时链接和运行时链接3种。
静态链接 是程序运行前将目标模块和库函数链接成完整的可执行文件,之后不再拆开。
装入时链接 是目标模块装入内存时,边装入边链接的方式。
运行时链接
是程序执行到某个目标模块,该目标模块引用到了其他模块时才将其他模块链接和装入内存(暂时用不到的模块不会装入内存)。优点是便于修改、更新和模块共享。
02 内存空间的扩充
内存空间的扩充有3种方式: 覆盖技术、交换技术 和 虚拟内存技术
。这3种技术都是以节省内存使用为目的,变着花样做到高效使用内存,让物理内存可以容纳尽可能多的进程个数。这3种技术都是根据局部性原理的思想设计出来的。
本节只介绍覆盖技术和交换技术,虚拟内存作为重点放到之后的章节介绍。
- 覆盖技术
覆盖技术用来解决单个程序大小超过物理内存总和的问题。
覆盖技术的思想是将程序分为多个段,让常用的段常驻内存,不常用的段放到外存,在需要用到这些不常用的段时才调入内存。
内存中划分一个固定区和若干个覆盖区,常驻内存的段放在固定区,调入固定区后不再调出直到程序运行结束。不常用的段放在覆盖区,需要运行到这些模块时才将其调入到覆盖区,不需要时将模块从覆盖区调出。

例如一个程序有一个主函数main,在main调用B和C,B和C不会被同时访问,同理D,E,F不会同时被访问,但运行D时A,B,D模块会同时被访问。
因此内存中会划分如图中的3个区域,共占用30K的物理内存。假如不采用覆盖技术,就需要将A~F模块都放到内存,那么就需要占用52K的物理内存。
覆盖技术的缺点是 对用户不透明,增加了编程负担 ,必须由程序员声明程序的模块结构,操作系统完成自动覆盖。覆盖技术只用于早期的操作系统中,现在已成为历史。
- 交换技术
交换技术又称为对换技术,其思想是内存空间紧张时系统将内存中某些进程暂时换出外存,在内存充足或者在某进程达到运行时机时把外存中的进程换入内存。换出再换入后,进程的数据段地址可能会发出变化。

交换技术需要关注以下问题:
1. 应该在外存(磁盘)的什么位置保存被换出的进程?

具有对换功能的操作系统中,通常把磁盘空间分为文件区和对换区两部分。
文件区用于存放文件,文件是离散的存储在文件区中的,主要是为了追求存储空间的利用率;
对换区空间用于存放被换出的进程数据,它只占磁盘空间的小部分。对换的速度直接影响到程序运行和系统调度速度,因此进程数据是连续的存储在对换区的,主要是为了追求更快的换入换出速度。
对换区的I/O速度比文件区的更快,这是因为连续存储意味着顺序IO,数据都存在同一磁道或相邻磁道,磁头定位时间大大缩减,读写数据的速度自然就更快。
2. 什么时候应该交换?
交换通常在许多进程运行且物理内存吃紧时进行,而内存负荷降低就会暂停对换。
例如操作系统在发现许多进程运行时经常发生缺页,就说明内存紧张,此时可以换出一些进程;如果缺页率明显下降,就可以暂停换出。
3. 应该换出哪些进程?
可优先换出 阻塞的进程 和
优先级低的进程。但是为了防止优先级低的进程在被调入内存后很快又被换出,有的系统还会将进程在内存的驻留时间作为是否换出该进程的考虑因素。
此外需要注意 PCB 会常驻内存,不会被换出到外存 。
覆盖和交换的区别在于覆盖是针对单个进程的内存调入调出,交换是不同进程之间换入换出。