.

内存你跑慢点行不行CPU跑慢点你养我吗内

主存(RAM)是一件非常重要的资源,必须要认真对待内存。虽然目前大多数内存的增长速度要比IBM要快的多,但是,程序大小的增长要比内存的增长还快很多。

不管存储器有多大,程序大小的增长速度比内存容量的增长速度要快的多。下面我们就来探讨一下操作系统是如何创建内存并管理他们的。

经过多年的研究发现,科学家提出了一种分层存储器体系(memoryhierarchy),下面是分层体系的分类

位于顶层的存储器速度最快,但是相对容量最小,成本非常高。层级结构向下,其访问速度会变慢,但是容量会变大,相对造价也就越便宜。(所以个人感觉相对存储容量来说,访问速度是更重要的)操作系统中管理内存层次结构的部分称为内存管理器(memorymanager),它的主要工作是有效的管理内存,记录哪些内存是正在使用的,在进程需要时分配内存以及在进程完成时回收内存。所有现代操作系统都提供内存管理。

下面我们会对不同的内存管理模型进行探讨,从简单到复杂,由于最低级别的缓存是由硬件进行管理的,所以我们主要探讨主存模型和如何对主存进行管理。

无存储器抽象

最简单的存储器抽象是无存储器。早期大型计算机(20世纪60年代之前),小型计算机(20世纪70年代之前)和个人计算机(20世纪80年代之前)都没有存储器抽象。每一个程序都直接访问物理内存。当一个程序执行如下命令:

MOVREGISTER1,

计算机会把位置为的物理内存中的内容移到REGISTER1中。因此呈现给程序员的内存模型就是物理内存,内存地址从0开始到内存地址的最大值中,每个地址中都会包含一个8位位数的内存单元。

所以这种情况下的计算机不可能会有两个应用程序同时在内存中。如果第一个程序向内存地址的这个位置写入了一个值,那么此值将会替换第二个程序位置上的值,所以,同时运行两个应用程序是行不通的,两个程序会立刻崩溃。

不过即使存储器模型就是物理内存,还是存在一些可变体的。下面展示了三种变体

在上图a中,操作系统位于RAM(RandomAccessMemory)的底部,或像是图b一样位于ROM(Read-OnlyMemory)顶部;而在图c中,设备驱动程序位于顶端的ROM中,而操作系统位于底部的RAM中。图a的模型以前用在大型机和小型机上,但现在已经很少使用了;图b中的模型一般用于掌上电脑或者是嵌入式系统中。第三种模型就应用在早期个人计算机中了。ROM系统中的一部分成为BIOS(BasicInputOutputSystem)。模型a和c的缺点是用户程序中的错误可能会破坏操作系统,可能会导致灾难性的后果。

按照这种方式组织系统时,通常同一个时刻只能有一个进程正在运行。一旦用户键入了一个命令,操作系统就把需要的程序从磁盘复制到内存中并执行;当进程运行结束后,操作系统在用户终端显示提示符并等待新的命令。收到新的命令后,它把新的程序装入内存,覆盖前一个程序。

在没有存储器抽象的系统中实现并行性一种方式是使用多线程来编程。由于同一进程中的多线程内部共享同一内存映像,那么实现并行也就不是问题了。但是这种方式却并没有被广泛采纳,因为人们通常希望能够在同一时间内运行没有关联的程序,而这正是线程抽象所不能提供的。

运行多个程序

但是,即便没有存储器抽象,同时运行多个程序也是有可能的。操作系统只需要把当前内存中所有内容保存到磁盘文件中,然后再把程序读入内存即可。只要某一时刻内存只有一个程序在运行,就不会有冲突的情况发生。

在额外特殊硬件的帮助下,即使没有交换功能,也可以并行的运行多个程序。IBM的早期模型就是这样解决的

System/是IBM在年4月7日,推出的划时代的大型电脑,这一系列是世界上首个指令集可兼容计算机。

在IBM中,内存被划分为2KB的区域块,每块区域被分配一个4位的保护键,保护键存储在CPU的特殊寄存器(SFR)中。一个内存为1MB的机器只需要个这样的4位寄存器,容量总共为字节(这个会算吧)

PSW(ProgramStatusWord,程序状态字)中有一个4位码。一个运行中的进程如果访问键与其PSW中保存的码不同,硬件会捕获这种情况。因为只有操作系统可以修改保护键,这样就可以防止进程之间、用户进程和操作系统之间的干扰。

这种解决方式是有一个缺陷。如下所示,假设有两个程序,每个大小各为16KB

从图上可以看出,这是两个不同的16KB程序的装载过程,a程序首先会跳转到地址24,那里是一条MOV指令,然而b程序会首先跳转到地址28,地址28是一条CMP指令。这是两个程序被先后加载到内存中的情况,假如这两个程序被同时加载到内存中并且从0地址处开始执行,内存的状态就如上面c图所示,程序装载完成开始运行,第一个程序首先从0地址处开始运行,执行JMP24指令,然后依次执行后面的指令(许多指令没有画出),一段时间后第一个程序执行完毕,然后开始执行第二个程序。第二个程序的第一条指令是28,这条指令会使程序跳转到第一个程序的ADD处,而不是事先设定好的跳转指令CMP,由于这种不正确访问,可能会造成程序崩溃。

上面两个程序的执行过程中有一个核心问题,那就是都引用了绝对物理地址,这不是我们想要看到的。我们想要的是每一个程序都会引用一个私有的本地地址。IBM在第二个程序装载到内存中的时候会使用一种称为

静态重定位(staticrelocation)的技术来修改它。它的工作流程如下:当一个程序被加载到地址时,常数被加到每一个程序地址上(所以JMP28会变为JMP)。虽然这个机制在不出错误的情况下是可行的,但这不是一种通用的解决办法,同时会减慢装载速度。更近一步来讲,它需要所有可执行程序中的额外信息,以指示哪些包含(可重定位)地址,哪些不包含(可重定位)地址。毕竟,上图b中的JMP28可以被重定向(被修改),而类似MOVREGISTER1,28会把数字28移到REGISTER中则不会重定向。所以,装载器(loader)需要一定的能力来辨别地址和常数。

一种存储器抽象:地址空间

把物理内存暴露给进程会有几个主要的缺点:第一个问题是,如果用户程序可以寻址内存的每个字节,它们就可以很容易的破坏操作系统,从而使系统停止运行(除非使用IBM那种lock-and-key模式或者特殊的硬件进行保护)。即使在只有一个用户进程运行的情况下,这个问题也存在。

第二点是,这种模型想要运行多个程序是很困难的(如果只有一个CPU那就是顺序执行)。在个人计算机上,一般会打开很多应用程序,比如输入法、电子邮件、浏览器,这些进程在不同时刻会有一个进程正在运行,其他应用程序可以通过鼠标来唤醒。在系统中没有物理内存的情况下很难实现。

地址空间的概念

如果要使多个应用程序同时运行在内存中,必须要解决两个问题:保护和重定位。我们来看IBM是如何解决的:第一种解决方式是用保护密钥标记内存块,并将执行过程的密钥与提取的每个存储字的密钥进行比较。这种方式只能解决第一种问题(破坏操作系统),但是不能解决多进程在内存中同时运行的问题。

还有一种更好的方式是创造一个存储器抽象:地址空间(theaddressspace)。就像进程的概念创建了一种抽象的CPU来运行程序,地址空间也创建了一种抽象内存供程序使用。地址空间是进程可以用来寻址内存的地址集。每个进程都有它自己的地址空间,独立于其他进程的地址空间,但是某些进程会希望可以共享地址空间。

基址寄存器和变址寄存器

最简单的办法是使用动态重定位(dynamicrelocation)技术,它就是通过一种简单的方式将每个进程的地址空间映射到物理内存的不同区域。从CDC(世界上最早的超级计算机)到Intel(原始IBMPC的核心)所使用的经典办法是给每个CPU配置两个特殊硬件寄存器,通常叫做基址寄存器(basicregister)和变址寄存器(limitregister)。

当使用基址寄存器和变址寄存器时,程序会装载到内存中的连续位置并且在装载期间无需重定位。当一个进程运行时,程序的起始物理地址装载到基址寄存器中,程序的长度则装载到变址寄存器中。在上图c中,当一个程序运行时,装载到这些硬件寄存器中的基址和变址寄存器的值分别是0和。当第二个程序运行时,这些值分别是和。如果第三个16KB的程序直接装载到第二个程序的地址之上并且运行,这时基址寄存器和变址寄存器的值会是和。那么我们可以总结下

基址寄存器:存储数据内存的起始位置变址寄存器:存储应用程序的长度。每当进程引用内存以获取指令或读取、写入数据时,CPU都会自动将基址值添加到进程生成的地址中,然后再将其发送到内存总线上。同时,它检查程序提供的地址是否大于或等于变址寄存器中的值。如果程序提供的地址要超过变址寄存器的范围,那么会产生错误并中止访问。这样,对上图c中执行JMP28这条指令后,硬件会把它解释为JMP,所以程序能够跳到CMP指令,过程如下

使用基址寄存器和变址寄存器是给每个进程提供私有地址空间的一种非常好的方法,因为每个内存地址在送到内存之前,都会先加上基址寄存器的内容。在很多实际系统中,对基址寄存器和变址寄存器都会以一定的方式加以保护,使得只有操作系统可以修改它们。在CDC中就提供了对这些寄存器的保护,但在Intel中则没有,甚至没有变址寄存器。但是,Intel提供了许多基址寄存器,使程序的代码和数据可以被独立的重定位,但是对于超出范围的内存引用没有提供保护。

所以你可以知道使用基址寄存器和变址寄存器的缺点,在每次访问内存时,都会进行ADD和CMP运算。CMP指令可以执行的很快,但是加法就会相对慢一些,除非使用特殊的加法电路,否则加法因进位传播时间而变慢。

交换技术

如果计算机的物理内存足够大来容纳所有的进程,那么之前提及的方案或多或少是可行的。但是实际上,所有进程需要的RAM总容量要远远高于内存的容量。在Windows、OSX、或者Linux系统中,在计算机完成启动(Boot)后,大约有50-个进程随之启动。例如,当一个Windows应用程序被安装后,它通常会发出命令,以便在后续系统启动时,将启动一个进程,这个进程除了检查应用程序的更新外不做任何操作。一个简单的应用程序可能会占用5-10MB的内存。其他后台进程会检查电子邮件、网络连接以及许多其他诸如此类的任务。这一切都会发生在

第一个用户启动之前。如今,像是Photoshop这样的重要用户应用程序仅仅需要MB来启动,但是一旦它们开始处理数据就需要许多GB来处理。从结果上来看,将所有进程始终保持在内存中需要大量内存,如果内存不足,则无法完成。

所以针对上面内存不足的问题,提出了两种处理方式:最简单的一种方式就是交换(swapping)技术,即把一个进程完整的调入内存,然后再内存中运行一段时间,再把它放回磁盘。空闲进程会存储在磁盘中,所以这些进程在没有运行时不会占用太多内存。

另外一种策略叫做虚拟内存(virtualmemory),虚拟内存技术能够允许应用程序部分的运行在内存中。下面我们首先先探讨一下交换

交换过程

下面是一个交换过程

刚开始的时候,只有进程A在内存中,然后从创建进程B和进程C或者从磁盘中把它们换入内存,然后在图d中,A被换出内存到磁盘中,最后A重新进来。因为图g中的进程A现在到了不同的位置,所以在装载过程中需要被重新定位,或者在交换程序时通过软件来执行;或者在程序执行期间通过硬件来重定位。基址寄存器和变址寄存器就适用于这种情况。

交换在内存创建了多个空闲区(hole),内存会把所有的空闲区尽可能向下移动合并成为一个大的空闲区。这项技术称为内存紧缩(memory


转载请注明:http://www.abachildren.com/sstx/7510.html