内存是CPU能直接存取指令和数据的存储器,本质是被分割为一个个以字或者字节为存储单元的存储空间,每个存储单元都有自己的地址,通过地址读写内存的数据。
CPU和IO系统都会直接与内存打交道。程序也要载入到内存之后才能运行。
存储单元
如果计算机按字节编址,则单个字节就是一个存储单元,每个字节都有一个地址;
如果计算机按字编址(字长可能为16位或32位等),则单个字就是一个存储单元,每个字都有一个地址;
内存管理
在介绍操作系统功能的时候,我们知道内存管理是OS的功能之一。那么OS的内存管理具体又包含哪些事情?
1.内存分配与回收;
2.逻辑上对内存空间进行扩展(覆盖技术、交换技术 和 虚拟内存);
3.地址转换(又称为重定位),将程序的逻辑地址转为物理地址;
4.内存保护,各个进程的内存空间互不干扰(两种方式:设置上限寄存器和下限寄存器;设置基址寄存器和限长寄存器)。
用户程序的地址空间
程序装入内存前发生了什么
编译:编译程序将高级语言翻译为机器指令,得到若干个目标模块;
链接:链接程序将编译后得到的目标模块以及所需库函数组合成一个完整的装入模块。
装入:装入程序将装入模块装入到内存中。
在编译阶段,程序不可能知道数据将来会在内存的哪个地址,因此编译生成的指令和数据的内存地址是逻辑地址(从0开始)。
将程序装入内存之后,每个指令和对应的数据才有自己的物理内存地址,因此将程序的逻辑地址转为物理地址是装入程序应该关注的事情。此外装入程序还负责为程序分配内存。
重定位
将程序的逻辑地址转为物理地址的过程称为重定位。
重定位按照时机分为3种。
绝对重定位是指编译时编译程序就知道程序会放在内存的哪个位置,由编译程序产生具有绝对地址的机器指令,装入程序再按绝对地址将程序和数据装入内存。
装入模块的地址(逻辑地址)与内存地址(物理地址)完全一致。
绝对装入只适合于单道程序环境,内存中只会有一个用户程序,想放在哪就放在哪。
静态重定位是指编译和链接后的装入模块的地址是相对地址,装入程序根据装入模块装入内存的开始位置对程序中的所有指令和数据的逻辑地址修改为物理地址。
地址重定位是在装入内存时一次性完成的。
缺点:
1.静态重定位要求作业装入内存时就为其分配所有的内存空间,并且运行期间不能移动程序在内存中的位置(因为重定位只发生在装入内存时,而不发生在运行时,运行时不能再做一次逻辑地址映射为物理地址,那么自然就不能移动程序在内存的位置),也不能再申请空间(不然你是不可能在装入时一次性完成地址映射的)。
2.程序的存储空间只能是连续的一片区域,不利于内存空间有效使用。
动态重定位又称动态运行时装入,即编译和链接后的装入模块的地址为相对地址,装入内存时也不会立刻将逻辑地址转为物理地址(此时程序中的地址还是逻辑地址),而是把地址转换推迟到指令执行时进行。
动态重定位需要硬件实现,所需硬件包括一对寄存器:存放用户程序在内存的起始地址(物理地址),称为基址寄存器;存放用户程序逻辑地址的最大范围,称为限长寄存器(保存地址长度)。运行指令时将指令内的相对地址+基址寄存器的值 就能得到物理地址。
动态重定位的好处如下
采用动态重定位时允许程序(数据段和代码段)在内存中发生移动。
程序可以离散存储在内存,减少内存碎片。
程序运行可以只装入部分代码,节省运行进程时占用的进程。
程序可以动态申请内存。
后面介绍的段式存储和页式存储都是动态重定位。
链接的三种方式
链接是将多个编译后的目标模块和用到的库函数合并为一个整体的可执行文件(装入模块)。
静态链接是程序运行前将目标模块和库函数链接成完整的可执行文件,之后不再拆开。
装入时链接是目标模块装入内存时,边装入边链接的方式。
运行时链接是程序执行到某个目标模块,它引用到了其他模块才将其他模块链接和装入内存(用不到的模块不会装入内存)。优点是便于修改、更新和模块共享。
内存空间的扩充
内存空间的扩充分为3种:覆盖技术、交换技术 和 虚拟内存技术。这3种技术都是以节省内存使用为目的,变着花样如何高效使用内存,让内存容纳更多进程。
这3种技术都是根据局部性原理的思想设计出来的。
覆盖技术
覆盖技术用来解决(单个)程序大小超过物理内存总和的问题。
覆盖技术的思想是将程序分为多个段(多个模块,我们可以简单的理解为代码块,例如一个函数、一个类),将常用的段常驻内存,不常用的段在需要时才调入内存。
内存中划分一个固定区和若干个覆盖区,常驻内存的段放在固定区,调入后不再调出(除非程序运行结束)。
不常用的段放在覆盖区,需要运行子模块时调入到覆盖区,不需要时将模块从覆盖区调出。
例如一个程序有一个主函数main,在main调用B和C,B和C不会被同时访问,同理D,E,F不会同时被访问,但运行D时A,B,D模块会同时被访问。
因此内存中会划分如图中的3个区域,共占用30K(如果不采用覆盖技术,就需要52K)。
覆盖技术的缺点是对用户不透明,增加了编程负担,必须由程序员声明程序的模块结构(因为操作系统在编译和链接时不知道程序的模块结构),操作系统完成自动覆盖。
覆盖技术只用于早期的操作系统中,现在已成为历史。
交换技术
交换(对换)技术的思想是内存空间紧张时系统将内存中某些进程暂时换出外存,在内存充足或者在某进程达到运行时机时把外存中 的进程换入内存。
换出再换入后,进程的数据段地址可能会发出变化。
交换技术需要关注以下问题:
1. 应该在外存(磁盘)的什么位置保存被换出的进程?
具有对换功能的操作系统中,通常把磁盘空间分为文件区和对换区两部分。
- 文件 区用于存放文件,主要追求存储空间的利用率,文件是离散的存储在文件区中的;
- 对换区空间只占磁盘空间的小部分,被换出的进程数据就存放 在对换区。对换的速度直接影响到程序运行和系统调度速度,因此对换区空间主要追求换入换出速度,进程数据是连续的存储在对换区的。对换区的I/O速度比文件区的更快(因为连续存储意味着顺序IO,数据都存在同一磁道或相邻磁道,磁头定位时间大大缩减)。
2. 什么时候应该交换?
交换通常在许多进程运行且内存吃紧时进行,而系统负荷降低就暂停对换。
例如:在 发现许多进程运行时经常发生缺页,就说明内存紧张,此时可以换出一些进程; 如果缺页率明显下降,就可以暂停换出。
3. 应该换出哪些进程?
可优先换出阻塞进程;可换出优先级低的进程;为了防止优先级低的进程在被调 入内存后很快又被换出(防止饥饿),有的系统还会考虑进程在内存的驻留时间。
注意:PCB 会常驻内存,不会被换出到外存。
覆盖和交换的区别在于覆盖是针对用一进程的内存调入调出,交换是在不同进程之间换入换出。