操作系统(5)

内存管理

程序在执行时,程序以及所访问的数据必须在内存里。内存由很大一组字或字节组成,每个字或字节都有自己的地址。CPU根据程序计数器从内存中提取指令,这些指令可能会引起进一步对内存地址的读取和写入。
CPU可以直接访问的存储器只有内存和处理器内的寄存器。如果数据不在内存内,CPU在使用前必须把数据移到内存中。
CPU内置寄存器通常在一个CPU周期中内完成访问,而对于内存(其访问通过内存总线上的事务进行)就不行了。解决方案是在CPU和内存之间增加高速内存。
我们首先要确保每个进程有独立的内存空间,为此需要确定进程可以访问的合法地址的范围,并确保进程只访问其合法地址。通过两个寄存器可以实现这种保护。基地址寄存器(base register)含有最小的合法物理内存地址,而界限地址寄存器(limit register)决定了范围的大小。如果基地址寄存器为300040,而界限地址寄存器为120900,那么可以访问300400到420940的所有地址。这种方案防止用户程序修改操作系统或其他用户的代码或数据结构。

地址绑定

通常程序以二进制可执行文件的形式存储在硬盘上,为了执行程序被调入内存并放在进程空间中(上面提到的内存空间)。在磁盘上等待调入内存以便执行的过程形成输入队列(input queue),通常是从输入队列中选择一个进程并装入内存,进程在执行时,会访问内存中的指令和数据。
通常,将指令与数据绑定到内存地址有以下几种情况:

  • 编译时(compile time):如果在编译时就知道进程在内存中的驻留地址,那么可以生成绝对代码(absolute code),例如如果事先知道用户进程驻留在内存地址R处,那么所生成的编译代码就可以从该位置开始并向后扩展。
  • 加载时(load time):如果编译时不知道进程将驻留在内存什么地方,那么编译器就要生成可重定位代码。对于这种情况,最后绑定会延迟到加载时进行。
  • 执行时(excusion time):如果进程在执行时可以从一个内存段移到另一个内存段,那么绑定必须延迟到执行时才进行。

逻辑地址空间与物理地址空间

CPU生成的通常为逻辑地址(logical address),而内存单元所看到的地址通常是物理地址(physical address)。
编译时和加载时的地址绑定方法生成相同的逻辑地址和物理地址,但是执行时的地址方案绑定导致不同的逻辑地址和物理地址。对于这种情况,通常称逻辑地址为虚拟地址(virtual address)。
运行时从虚拟地址到物理地址的映射是由内存管理单元(memory-management unit)的硬件设备来完成的。基地址寄存器在这里被称为重定位寄存器,用户进程所生成的地址在送交内存之前,都将加上重定位寄存器的值,完成从逻辑地址到物理地址的映射。

动态加载

一个进程的整个程序和数据必须处于物理内存中以便执行,为了获得更好的内存空间使用率,可以使用动态加载(dynamic loading)。采用动态加载时,一个子程序只有在调用时才被加载。

交换

进程可以暂时从内存中交换到备份存储(backing store)上,当需要再次执行时再调回到内存中。例如,有一个CPU调度算法采用轮转法的多道程序环境,当时间片用完,内存管理器将刚刚执行过的进程换出,将另一进程换入到刚刚释放的的内存空间中。交换需要备份存储,备份存储通常是快速硬盘。

连续内存分配

内存必须容纳操作系统和各种用户进程,因此应该尽可能有效地分配内存的各个部分。通常需要把多个进程同时放在内存中,因此需要考虑如何为输入队列中调入内存的进程分配内存空间,采用连续内存分配时,每个进程位于一个连续的内存区域。
上面说到的重定位寄存器和界限地址寄存器,实现了内存保护和内存映射,最终将逻辑地址处理成物理地址。
最简单的分配内存方法就是将内存分为多个固定大小的分区(partition),每个分区只能容纳一个进程。当一个分区空闲的时候,可以从输入队列中选择一个进程,以调入到空闲分区。在这个方案中,操作系统中有一个表,用来记录哪些内存可用和哪些内存被占用。

猜你喜欢

转载自blog.csdn.net/sysuzhyupeng/article/details/78459204