操作系统概述(二)

操作系统内存管理

内存管理包括内存管理和虚拟内存管理。
内存管理包括程序装入等概念、交换技术、连续分配管理方式和非连续分配管理方式(分页、分段、段页式)。
虚拟内存管理包括虚拟内存概念、请求分页管理方式、页面置换算法、页面分配策略、工作集。

我们先来了解一下什么是内存:

内存是计算机系统的一个重要组成部分,只有在内存中的程序才能被CPU所执行,而且CPU运行时所需要的数据和程序运行空间都是从内存中获取,所以内存性能的好坏直接影响我们计算机性能的好坏.

讲到内存我们可以讲一下关于存储器的分类:

存储器按照功能分配可以分为高速缓冲存储器(cache),主存储器(内存),外存储器(外存):

高速缓冲存储器(cache):cache又分为一级cache和二级cache,一级cache是位于CPU内部的存储器,它负责存储并向CPU传递需要的数据和指令,二级cache位于CPU和主存储器(DRAM)之间,二级的作用就是存储那些CPU处理时需要用到、一级缓存又无法存储的数据。CPU读取数据时,先从一级cache中寻找,找不到再从二级cache中寻找,有时还需要从三级cache中寻找.它们的共同点是读取速度都比CPU慢比内存快,内存容量小,价格高. 缓存的出现主要是为了解决CPU运算速度与内存 读写速度不匹配的矛盾,因为CPU运算速度要比内存读写速度快很多,这样会使CPU花费很长时间等待数据到来或把数据写入内存。

主存储器(内存): 我们手机或者电脑所说的运行内存便是主存储器,程序运行时会把处于外存的数据调换到主存中,主存里面存放着大量的CPU运行时可能需要用到的数据,它的特点时读写速度较快,大小较小.一般为4G-8G大小.

外存储器(外存):外存也就是我们常说的硬盘,它负责存放系统程序和大型数据文件及数据库,特点就是容量大,速度低.

按照存储器的类别我们又可以分为以下几类:

RAM
RAM(random access memory,随机存取存储器)。存储单元的内容可按需随意取出或存入,且存取的速度与存储单元的位置无关的存储器。这种存储器在断电时将丢失其存储内容,故主要用于存储短时间使用的程序。 按照存储信息的不同,随机存储器又分为静态随机存储器(Static RAM,SRAM)和动态随机存储器(Dynamic RAM,DRAM)。

SRAMS
RAM(Static RAM,静态随机存储器),不需要刷新电路,数据不会丢失,而且,一般不是行列地址复用的。但是他集成度比较低,不适合做容量大的内存,一般是用在处理器的缓存里面。
SRAM其实是一种非常重要的存储器,它的用途广泛。SRAM的速度非常快,在快速读取和刷新时能够保持数据完整性。SRAM内部采用的是双稳态电路的形式来存储数据。所以SRAM的电路结构非常复杂。制造相同容量的SRAM比DRAM的成本高的多。正因为如此,才使其发展受到了限制。因此目前SRAM基本上只用于CPU内部的一级缓存以及内置的二级缓存。仅有少量的网络服务器以及路由器上能够使用SRAM。

DRAM
Dynamic RAM,动态随机存取存储器,每隔一段时间就要刷新一次数据,才能保存数据。而且是行列地址复用的,许多都有页模式。SDRAM是其中的一种。

SDRAM
SDRAM(Synchronous DRAM,同步动态随机存储器),即数据的读写需要时钟来同步。其存储单元不是按线性排列的,是分页的。
DRAM和SDRAM由于实现工艺问题,容量较SRAM大。但是读写速度不如SRAM。
一般的嵌入式产品里面的内存都是用的SDRAM。电脑的内存也是用的这种RAM,叫DDR SDRAM,其集成度非常高,因为是动态的,所以必须有刷新电路,每隔一段时间必须得刷新数据。

ROM
Read-Only Memory,只读存储器的总称。
在微机的发展初期,BIOS都存放在ROM(Read Only Memory,只读存储器)中。ROM内部的资料是在ROM的制造工序中,在工厂里用特殊的方法被烧录进去的,其中的内容只能读不能改,一旦烧录进去,用户只能验证写入的资料是否正确,不能再作任何修改。如果发现资料有任何错误,则只有舍弃不用, 重新订做一份。ROM是在生产线上生产的,由于成本高,一般只用在大批量应用的场合。

PROM
可编程只读存储器,只能写一次,写错了就得报废,现在用得很少了,好像那些成本比较低的OPT单片机里面用的就是这种存储器吧。

EPROM 
EPROM(Erasable Programmable ROM,可擦除可编程ROM)芯片可重复擦除和写入,解决了PROM芯片只能写入一次的弊端。
EPROM芯片有一个很明显的特征,在其正面的陶瓷封装上,开有一个玻璃窗口,透过该窗口,可以看到其内部的集成电路,紫外线透过该孔照射内部芯片就可以擦除其内的数据,完成芯片擦除的操作要用到EPROM擦除器。

EEPROMEEPROM (Electrically Erasable Programmable ROM,电可擦可编程只读存储器),一种掉电后数据不丢失的存储芯片。EEPROM是可用户更改的只读存储器,其可通过高于普通电压的作用来擦除和重编程(重写),即可以在电脑上或专用设备上擦除已有信息并重新编程。不像EPROM芯片,EEPROM不需从计算机中取出即可修改,是现在用得比较多的存储器,比如24CXX系列的EEPROM。
在一个EEPROM中,当计算机在使用的时候是可频繁地重编程的,EEPROM的寿命是一个很重要的设计考虑参数。

闪存(Flash)
闪存(FLASH)是一种非易失性存储器,即断电数据也不会丢失。因为闪存不像RAM(随机存取存储器)一样以字节为单位改写数据,因此不能取代RAM。   
闪存卡(Flash Card)是利用闪存(Flash Memory)技术达到存储电子信息的存储器,一般应用在数码相机,掌上电脑,MP3等小型数码产品中作为存储介质,所以样子小巧,有如一张卡片,所以称之为闪存卡。根据不同的生产厂商和不同的应用,闪存卡大概有U盘、SmartMedia(SM卡)、Compact Flash(CF卡)、MultiMediaCard(MMC卡)、Secure Digital(SD卡)、Memory Stick(记忆棒)、XD-Picture Card(XD卡)和微硬盘(MICRODRIVE)。这些闪存卡虽然外观、规格不同,但是技术原理都是相同的。

NAND FLASH和NOR FLASH都是现在用得比较多的非易失性闪存。
程序的执行过程

执行程序要将程序和数据装入内存。将用户源程序变为可在内存中执行的程序,通常需要以下几个步骤:

编译:由编译程序将用户源代码编译成若干个目标模块。
链接:由链接程序将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块。
装入:由装入程序将装入模块装入内存运行。

程序的链接又分为以下几类:

静态链接:程序在执行前,将各个模块以及它们需要用到的库函数链接成可执行文件.
装入时动态链接:程序在编译完之后得到一组目标模块,在装入内存时链接在一起.
运行时动态链接:程序在运行前还是离散的,在运行时把运行所需要的模块链接在一起.

程序的装入分为以下几类:

绝对装入:在编译时,如果知道程序将驻留在内存的某个位置,编译程序将产生绝对地址的目标代码。绝对装入程序按照装入模块中的地址,将程序和数据装入内存。由于程序中的逻辑地址与实际内存地址完全相同,故不需对程序和数据的地址进行修改。
可重定位装入:在多道程序环境下,多个目标模块的起始地址通常都是从 0 开始,程序中的其他地址都是相对于起始地址的,此时应釆用可重定位装入方式。根据内存的当前情况,将装入模块装入到内存的适当位置。装入时对目标程序中指令和数据的修改过程称为重定位,地址变换通常是在装入时一次完成的,所以又称为静态重定位。
静态重定位的特点是在一个作业装入内存时,必须分配其要求的全部内存空间,如果没有足够的内存,就不能装入该作业。此外,作业一旦进入内存后,在整个运行期间不能在内存中移动,也不能再申请内存空间。
动态运行时装入,也称为动态重定位:程序在内存中如果发生移动,就需要釆用动态的装入方式。装入程序在把装入模块装入内存后,并不立即把装入模块中的相对地址转换为绝对地址,而是把这种地址转换推迟到程序真正要执行时才进行。因此,装入内存后的所有地址均为相对地址。这种方式需要一个重定位寄存器的支持。
动态重定位的特点是可以将程序分配到不连续的存储区中;在程序运行之前可以只装入它的部分代码即可投入运行,然后在程序运行期间,根据需要动态申请分配内存;便于程序段的共享,可以向用户提供一个比存储空间大得多的地址空间。

系统分区

内存分为两个区域,一个用来存放操作系统,一个用来存放用户进程,当进程调入内存是我们需要为它分配一块内存空间,在这里我们采用的是连续内存分配,一个进程存放在连续的一段内存空间内。
内存保护

内存保护是为了防止用户进程影响操作系统或者用户进进程影响其他进程,操作系统通过采用重定位寄存器和界地址寄存器来实现这种保护,重定位寄存器里面包含最小物理地址,界地址寄存器包含最小的逻辑地址,每个进程的逻辑地址必须小于界地址寄存器,内存管理单元动态地将逻辑地址与界地址进行比较,若未发生越界,则再加上重定位寄存器里的地址值找到物理地址,再送到内存单元。
连续内存分配管理

为了能将程序装入内存,必须为它分配一定大小的内存空间,连续分配是最早出现的一种存储器分配方式·,该分配方式为用户程序分配了一个连续的内存空间,即程序的代码或者数据的逻辑地址相邻 ,体现在内存空间分配时物理地址的相邻。连续分配方式可分为四类:单一连续,固定分区分配,动态分区分配以及可重定位分区分配(紧凑)算法四种方式:

单一连续分配。内存此时分为系统区和用户区,系统区只分配给操作系统使用,通常在低地址部分;用户区为用户提供。内存中只有一道程序,也无需进行内存保护。无外部碎片但是有内部碎片,且存储器效率低下。
固定分区分配。将内存空间划分为若干个固定大小的区域,每个分区只能装入一道作业。当有空闲分区时,便可以再从外存的后备作业队列中,选择适当大小的作业装入该区,分为(分区大小相等和分区大小不相等两种方式)无外部碎片但是有内部碎片(分区内部有空间的浪费),且存储器效率低下,但是可存在多道程序,是用于多道程序并发执行的最简单的内存分配方式。

动态分区分配。也成为可变分区分配,它不预先对内存进行划分,而是在进程装入内存时,根据进程的大小动态的建立分区,并使分区的大小正好适合进程的需要,其分区的数目和大小是可变的。但是随着时间的推移,很容易产生外部碎片,外部碎片指的是分区以外的存储空间被浪费
基于顺序搜索的动态分区分配算法:

首次适应算法,空闲分区以地址递增的方式链接,分配内存时顺序查找,找到大小满足要求的第一个空闲分区,通常该算法是最快最好的也是最简单的。http://www.daiqiyang.com
最佳适应算法,空闲分区以容量递增形成分区链,找到第一个满足要求的空闲分区,实际上新能不佳,因为每次最佳分配通常会留下很小的难以利用的内存块,产生外部碎片。
最坏适应算法,又称最大适应算法,空闲分区以容量递减形成分区链,找到第一个满足要求的空闲分区,也就是挑选出最大的分区性能较差,因为算法开销也是需要考虑的一部分
邻近适应算法,又称循环首次适应算法,也就是从首次适应算法中演变而来,不同的是,从上次查找结束的位置开始继续查找性能较差

分段和分页机制

要理解分段和分页,首先我们要知道为什么会出现分段和分页这两项技术;

首先我们要知道分段和分页都是为了更好的管理计算机的资源--内存。

在分段技术还没出来之前,程序在内存运行之前都是先从内存中寻找找到连续的一片地址空间,比如我们程序A需要10M的空间,那么就要从内存空间里寻找出10M的地址空间,然后再把A装入进去,如果没找到连续的空间,那么就不予分配。

从这里我们可以看出以前的内存分配的缺点;

地址空间不隔离,假如我们两个程序A和B,A存放在0x000001~0x0000999这个内存空间,B存放在0X0001000~0x0001100这个空间里,那如果我们对A的操作地址0x0000500误写为0x0001050,那么我们不仅没有对A实施正确的操作,还影响了程序B的执行。
程序地址的不确定,因为我们现在都是对内存地址直接操作,所以我们程序需要写死要操作的某个内存的地址,但是如果我们想要操作地址0x0000001000,我们就必须写死我们要操作的地址为0x0000001000,但是这样问题来了,我们程序运行时在内存的地址在不同时候可能不一样,比如我们第一次可能在内存中的地址为0x0000000001~0x00000100000;那么我们第一次操作可能就没有问题,但是第二次运行时他在内存中的地址可能就变为0x000000100000~0x00000110000,那么我们第二次运行是我们想要操作的地址根本程序占有的内存里,我们可能又误操作其他程序的数据了。
内存使用率低,假如我们内存大小为70M,我们有A B C三个程序在内存中分别连续占20M  10M  30M的地址空间,当我们B运行完被置换出来时A和C中间就有10M的内存空间,然后我们有大小为11M的程序D想要装入内存,然后它从内存中寻找一个11M的连续地址空间,然后我找到了两个10M的地址空间,但是它们是不连续的,所以程序没办法装入内存中,只能等待A或者C运行完才能装入,这样这20M的内存空闲地址就没有被利用起来。

为了解决这些问题,人们就去寻找一种办法来解决它,所以分段技术就出来了:

为了实现分段技术,人们又引入了虚拟地址空间的概念,什么是虚拟地址空间呢,就是这个空间真实不存在,只是我们为了更好地操作物理地址而引出的一个概念,简单来说就是我们的程序在运行前它的操作都是虚拟地址;例如,程序A的虚拟地址空间是0x00000100~0x100000200,此时,我们不仅需要一块连续的物理内存来存放A,还需要把A的虚拟地址映射到物理地址空间,可能A的虚拟地址空间是从0x00000100~0x100000200映射到物理地址空间0x00000000~0x00000100;

那么分段是什么呢?

分段机制就是把虚拟内存组织成一些长度可变的称为段的内存单元,通过段表来管理这些段,每个段定义了一组逻辑信息,每个程序可以有多个段,如数据段,代码段等,每个段都是一段连续的地址空间,段的长度由程序的大小决定,所以各个段的长度不等,所以段的地址空间是二维的,由段首地址和段长组成;

分段的作用是什么?

段的共享和保护:在这里我们讲一下段的保护机制,段的保护机制分为越界检查和权限检查,越界检查是段表寄存器中存放着段表信息,里面包括段的起始地址和段的长度,在进行存储访问时,首先将逻辑地址空间的段号与段表长度进行比较,如果段号等于或大于段表长度,将发出地址越界中断信号,其次还要检查段内地址是否大于段长,若大于段长,将产生越界中断信号,从而保证每个进程只能在自己的地址空间运行。权限检查就是在段表的每个表项中,都设置了‘存取控制’字段,用于规定对该段的访问方式,通常的访问方式有只读,只执行,读/写。通过段保护和共享可以解决一个程序对其他程序的影响的问题。

段的地址变换机制:分段管理可以提供逻辑地址到物理地址的转换,逻辑地址到物理地址通过地址映射表完成,所以只有虚拟地址没有改变,那么我们就不需要关心程序在内存的物理地址是什么,所以通过段的地址映射机制可以解决问题2。

但是我们的问题3还是没有解决,内存的利用率还是没有解决,所以我们引出了分页管理

分页管理是把主存空间分为大小相等且固定的块,块的大小较小,作为主存的基本单位,页表存储着这些页的基本信息,每个进程对应一个页表,(进程中的块称之为页,主存中的块称为页框,外存中称之为块,进程在执行时,向主存申请块,就产生了页与页框的一一对应关系)如图:

如何利用分页机制解决外部碎片呢,我们利用分页单元把一组非连续的空闲页框映射到连续的线性地址,这样他们在物理上不连续但是在逻辑上是连续的,这样就是有效的解决外部碎片问题。

而在linux中采用了著名的伙伴算法来解决外部碎片问题。把所有的空闲页框分组为11个块链表,每个链表分别包含大小为1,2,4,8,16,32,64,128,256,512,1024个连续的页框,对1024个页框的最大请求对应着4MB大小的连续RAM(每页大小为4KB),每个块的第一个页框的物理地址是该块大小的整数倍,例如,大小为16个页框的块,其起始地址是16*2^12的倍数。
我们通过一个例子来说明伙伴算法的工作原理,假设现在要请求一个256个页框的块(1MB),算法步骤如下:
• 在256个页框的链表中检查是否有一个空闲快,如果没有,查找下一个更大的块,如果有,请求满足。
• 在512个页框的链表中检查是否有一个空闲块,如果有,把512个页框的空闲块分为两份,第一份用于满足请求,第二份链接到256个页框的链表中。如果没有空闲块,继续寻找下一个更大的块。如图:

以上过程的逆过程,就是页框块的释放过程,也是该算法名字的由来,内核试图把大小为B的一对空闲伙伴块合并为一个2B的单独块,满足以下条件的两个块称之为伙伴:
• 两个块具有相同的大小http://www.daiqiyang.com
• 他们的物理地址是连续的
第一块的第一个页框的物理地址是2 B 2^12
该算法是递归的,如果它成功合并了B,就会试图去合并2B,以再次试图形成更大的块。

分段和分页是区别:

1、分页机制会使用大小固定的内存块,而分段管理则使用了大小可变的块来管理内存。

2、分页使用固定大小的块更为适合管理物理内存,分段机制使用大小可变的块更适合处理复杂系统的逻辑分区。

3、段表存储在线性地址空间,而页表则保存在物理地址空间。

4,分页的作业地址空间是一维的,即单一的线性空间,程序员只须利用一个记忆符(线性地址的16进制表示),即可表示一地址。

分段的作业地址空间是二维的,程序员在标识一个地址时,既需给出段名(比如数据段、代码段和堆栈段等),又需给出段内地址。

猜你喜欢

转载自blog.51cto.com/6624835/2462933