存储器的多层结构
在一个操作系统中,我们的程序不是运行在磁盘上,而是运行在操作系统的内存中。内存,广义上可以认为就是我们电脑中的内存条,这也是为什么内存越大,运行的程序支持的越大/多。
内存,只是计算机设备存储器的一部分。对于一个计算机而言,存储器具有多层结构,如下图所示:
需要说明的是,硬盘缓存存在硬盘上,当进程通过suspend原语被挂起后会被移出内存到硬盘中,其存在的位置就位于硬盘缓存;高速缓存,不同于硬盘缓存,它是一个独立的结构,运行效率高于主存储器(内存),直接与寄存器连接。
进程运行的准备工作
我们这里所说的进程运行的准备工作,针对进程是如何被加载到内存中的过程。其具体过程如下图:
程序的装入
绝对装入
指定内存中明确的位置装入程序,该指定位置不可改变。正是由于整个特性,这种方式适用于单道程序,否则多个程序的话很容易导致“串台”。
可重定位装入
装入程序会根据程序指定的内存位置将需要运行的程序分配(如果指定位置被占用,重新计算位置)到“合适的位置”,即空闲空间中。
动态运行时装入
绝对装入以及可重定位装入有个共同的特点,那就是装入时将会分配整个程序所需的内存大小。而动态运行时装入方式,允许在装入时仅仅装入程序部分内容,在允许过程中程序可以自行申请新的内存资源。
两个细节
逻辑地址与物理地址
物理地址:进程在内存中的实际地址;
逻辑地址:在程序中,会认为程序运行时的地址从0开始;
由于逻辑地址必须要能够映射到实际的物理地址,因此我们在地址转换时(装入时)存在一个步骤:地址重定位。
内存保护
当内存中存在多个运行的进程,假如有程序正在进行装入过程,那么必须避免正在运行的进程取访问装入程序的内存地址。
为了达到这个目的,通常会记录程序在内存中的地址起始值以及结束值/偏移量。只要知道了地址的范围,自然就可以防止其他进程对范围内的地址进行操作。
用户程序 -> 进程
从用户程序成为进程的过程要经历编译、链接、装入三个过程。我们再来看看这幅图:
首先,操作系统的编译程序针对我们自己的程序模块进行编译。编译完成后操作系统的链接程序结合操作系统的库对编译结果进行封装,也就形成了装入模块。最后在操作系统的装入程序下,完成程序的装入工作。
程序的链接
- 静态链接:在程序装入之前就完成了链接;
- 装入时动态链接:原理是在链接程序完成部分时,就开始进行装入过程,不必等待程序链接完成后再开始装入过程;
- 运行时动态链接:与装入时类似,当运行的进程需要某些模块时,发生中断,进程部分程序的编译、链接、装入;
内存扩充的两种方式
覆盖
在部分程序装入后,所分配的内存划分为两个区域,分别是固定区、覆盖区。再后续进行的程序装入过程中,其可以装入到覆盖区。这样在逻辑上就完成了内存的扩充。
交换
不同于覆盖方式的操作对象仍然是内存,交换的操作对象是硬盘缓存区域(就是硬盘上)。一个程序在内存中可能存在多个进程,操作系统可以考虑将不活跃的进程暂时交换到硬盘缓存中,达到内存扩充的目的。