操作系统—内存篇

内存的基本概念

内存是用于存放数据的硬件,程序执行前需要先放到内存中才能被CPU处理

内存地址是从0开始的,每个地址对应一个储存单元。如果计算机“按字节编址”则每个存储单元的大小为一字节;也就是1B,即8个二进制位。如果字长为16位的计算机“按字编址”,则每个存储单元大小为1个字节,每个字的大小为16个二进制位。

编译时产生的指令只关心‘相对位置’(逻辑地址),实际放入内存中时再根据起始位置得到‘绝对位置’(物理地址)

编译:把高级语言翻译成低级语言(机器语言)的过程。

链接:由链接程序将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块。最终由装入模块形成一个完整的物理地址。

逻辑地址转换到物理地址的三种方式:

1.绝对装入:在编译时,如果知道程序将放在内存中的那个位置,编译程序将产生的绝对地址的目标代码。(只适用于单道程序环境)

2.静态重定位:又称重定位装入,编译,链接后的装入模块的地址都是从0开始的,指令使用的地址,数据存放的地址都是相对于起始位置而言的逻辑地址。可以根根据内存的当前情况,将装入模块装入到内存的适当位置。装入时对地址重定位,将逻辑地址变化为物理地址。(作业装入内存时必须分配其要求的全部内存空间,如果没有足够的内存,就不能装入。一旦装入,在运行期间就不能移动)

3.动态重定位:又称为动态运行时装入,装入程序把装入模块装入内存后,并不会立刻把逻辑地址转化为物理地址,而是把地址转化推迟到程序真正要执行时才进行。

链接的三种方式:

1.静态链接:在程序运行前先将各个目标模块以及它们所需要的库函数连接成一个完整的执行文件(装入模块)

2.装入时动态链接:将各个目标模块装入内存时,变装入便链接的方式。

3.运行时动态链接:在程序执行时需要那个模块,才会将那个模块进行链接,可以实现便于修改和更新的优点

内存保护:方法一,在CPU中设置一对上下限寄存器,用来存放进程的上下限地址,进程访问某个地址时,CPU会检查是否越界;方法二,采用重定位寄存器和界地址寄存器进行越界检查。重定位寄存器存放起始物理地址,界寄存器存放进程的最大逻辑地址

覆盖与交换

覆盖技术

覆盖技术的思想是把程序分成多个段,常用的段常驻内存,不常用的段在需要时调入内存,内存中分为固定区和若干个覆盖区。

这种技术必须由程序员声明覆盖结构,操作系统自动覆盖,对用户不透明,增加了用户编程负担。

交换技术

当内存空间紧张的时候,系统将内存中的某些进程(有限换出阻塞或优先级低的进程)换出外存,把外存中某些已经具备运行条件的进程换入内存(进程在内存与磁盘空间动态调度)(中级调度)

覆盖在同一个程序或进程中进行的;交换是在不同的进程或作业之间进行的

连续分配管理方式

单一连续分配方式

在这种分配方式下,内存被分为系统区和用户区,系统区通常位于内存的低地址部分,用户区用于存放用户进程相关数据。内存中只能有一道用户程序,不支持并发运行。

固定分区分配

将用户去划分成若干个固定大小的分区,在每个分区中只装入一道作业。有分区大小相等(缺乏灵活性,但适用于控制多个相同对象的场合)和分区大小不等(增加了灵活性,可以满足不同大小的进程需求)

操作系统通过建立分区说明表的数据结构来对各个分区进行管理记录每个分区的大小,起始地址,状态等。会产生内部碎片

动态分区分配

又称可变分区分配,这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的的大小动态建立分区,使分区的大小正好是进程所需要的。

操作系统使用空闲分区表或空闲分区链的方式记录内存的使用情况

有多个空闲分区时,需要按照动态分区算法选出一个分区分配给作业

如果两个空闲分区相邻,需要对这两个分区进行合二为一的操作,在分区表(链)中修改参数,表项

内部碎片:分配给某进程的内存区域中,有些部分没用用上;

外部碎片:指内存中某些空闲分区由于太小而难以利用

可以采用**紧凑(拼凑)**技术来解决外部碎片

动态分区分配算法

首次适应算法

每次从低地址开始查找,找到第一个能满足大小的空闲分区。(更大可能保留高地址部分的大分区)

空闲分区以地址递增的次序排列,每次分配内存时顺序查找空闲分区链(表)

最佳适应算法

尽可能多地留下大片的空闲区,优先使用更小的空闲区。把空闲分区按容量递增的次序链接,每次分配时顺序查找空闲分区链(表),在分配完毕后对整个分区链重新划分排序。这种算法会留下越来越多的小碎片,会产生很多外部碎片

最坏适应算法

又称最大适应算法,在每次分配时优先使用最大的连续空间,这样分配后的剩余空间就不会太小,方便使用。空闲分区按容量递减,每次分配时顺序查找空闲分区链(表)

临近适应算法

空闲分区已地址递增顺序排列,每次分配内存时从上次查找结束的位置开始查找空闲分区链(表),找到第一个满足要求的空闲分区(只更新表项,不会重新排列,开销较小,但可能导致高地址部分没有大进程分配)

非连续分配管理方式

基本分页储存管理

原理:如果把分区大小设置的更小一些,内部碎片会更小,内存利用率会更高。

将内存分区分为一个个大小相等的分区,每个分区就是一个页框(或称页帧,内存块,物理块),每个页框有一个编号,即‘ 页框号 ’(或称‘内存块号,页帧号,物理块号)页框从0开始。将用户进程的地址空间也分为与页框大小相等的一个个区域,称为“页”或“页面”,每个页面有一个编号,也就是 页号 。页框不能太大,否则会产生过大的内部碎片。进程中的页面与内存的页框有一一对应的关系,各个页面不必连续存放,也不必按先后顺序存放。

用这种方式计算实际地址,要先算出逻辑地址对应的页号,同时要知道该页号对应页面的起始地址,算出逻辑地址在页面中的偏移量。物理地址 = 页面始址+页内偏移量。

计算机使用2的n次幂来表示逻辑地址,后n位表示偏移量,其余位数表示页号。

为了知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张页表,用于记录进程页面和实际存放的内存块之间的对应关系。进程的每一页对应一个页表项(放在内存(页框)中)。每个页表项由页号和页块组成

页号可以是隐含的,只要知道页表存放的起始地址和页表项长度,就可以找到各个页号对应的页表项存放的位置

基本地址变换机构

系统中通常会设置一个页表寄存器(PTR),存放页表在内存中的的起始地址f和页表长度M,进程未执行时,页表的始址和页表长度放入PCB中,当进程被调度时,操作系统内核会把他们放入页表寄存器当中。

地址的转换过程:根据逻辑地址计算出页号和页内偏移量,判断页号是否中断决定是否越界中断,查询页表(第一次访问内存),找到页号所对应的页表项,确定页面所存放的内存块好,用内存块号和页内偏移量计算出物理地址,访问物理地址中对应的内存单元(第二次访问内存)

在页式管理中,地址是一维的。只要给出一个逻辑地址,并确定页面大小。系统就可以自动算出页号,页内偏移量两个部分。

为了方便页表的查询,经常会让页表项占用更多的字节,使得每个页面恰好可以装下整数个页表项。

具有快表的地址变换机构

局部性原理

时间局部性:如果执行了程序中的某条指令(访问了某个数据),那么不久后这条指令(数据)很可能再次被执行(访问)

空间局部性:一旦访问了某个储存单元,那么不久之后,其附近的储存单元也很可能被访问

由于局部性原理可以看出,查询内存中的页表时,可能很多次查到的都是同一个页表项

快表机制

快表又称**联想寄存器(TLB)**是一种访问速度比内存快得多的高速缓存储存器,用来存放当前访问的若干个页表项,以加快地址变换的过程。

在查询前会先查询快表(存放在更高速的存储器中),如果没有的话会将页号和内存块号存入快表并继续查找,如果有对应的页号,就可以直接知道对应的块号,直接得到物理地址并访问(仅需要一次访存)。如果快表已满,则需要一定算法对旧的页表项进行替换。

两级页表

单级页表的缺点:页表项占据大量空间,而且没有必要让整个页表都常驻内存。

两级页表:对长页表进行分组,使每个内存块正好放入一个分组,这些分组离散地放在各个内存块中。同时,要为离散分配的页表再建一个页表,称为页目录表(外层页表,顶层页表)

两级页表中,页表会分为一级页表和二级页表,实现地址变换时,先根据一级页号查出对应的内存地址,读出二级页表,在二级页表中用二级页号查出最终想要访问的地址位置。

二级页表中会有一个标志位来记录页面是否已经调入内存,如果没有调入内存,就会产生缺页中断(内中断),然后将目标页面从外存调入内存

若采用多级页表机制,则各级页表的大小不能超过一个页面

采用两级页表的访存:

第一次访存:访问内存中的页目录表;

第二次访存:访问内存中的二级页表;

第三次访存:访问目标内存单元

基本分段储存管理

进程的地址空间会按照程序自身的逻辑关系(主函数,子函数,全局变量等)划分若干段,每个段都有一个段名(在低级语言中,程序员使用段名来变成),每段从0开始编址。

内存分配规则:以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。

分段系统中的逻辑地址由段号(段名)和段内地址(段内偏移量)所组成

段号的位数决定了每个进程最多可以分为几个段

段内地址位数决定了每个段的最大长度是多少

编译时段名会被编译成段号,单元会被编译位段内地址

段表

用于记录各个段的存放位置,操作系统会位每个进程建立一张段映射表,每个段对应一个段表项,其中记录了该段在内存中的起始位置(基址)和段的长度

每个段表项的长度是相同的,因此段号可以隐含的,不占存储空间

段储存中逻辑地址转为物理地址

CPU在切换进程恢复运行环境时会恢复段表寄存器(存放段表地址和段表长度),找到内存中对应的段表,当访问逻辑地址时,可以根据逻辑地址得到段号和段内地址,根据段号判断是否越界,如果越级进行中断处理,否则继续执行,查询段表,找到对应的段表项,检查段内地址是否超过段长,最后根据段基址和段内地址算出物理地址。

分段、分页管理的对比

页是信息的物理单位,分页的主要目的是实现离散分配,提高内存利用率,分页是系统行为,对用户不可见;

段是信息的逻辑行为,分段的目的是更好的满足用户需求。分段对用户是可见的,用户编程时需要显式地输出段名

页的大小固定且由系统决定,段的长度不固定,决定于用户编写的程序。

分页的用户进程地址空间是一维的,程序员只需要给出一个助记符即可表示一个地址。

分段的用户进程地址空间是二维的,程序员在标识一个地址时,既要给出段名,又要给出段内地址。

分段相比于分页更容易实现信息的共享(让各进程的段表项指向同一个段即可)与保护,而页面不按逻辑划分,就很难实现共享

段页式管理方式

进程会按照逻辑模块分段,再将各段分页,再将内存空间分为大小相同的内存块/页框/页帧/物理块。进程会将各页面分别装入各内存块中

段页式系统的逻辑地址结构由段号,页号和页内地址(页内偏移量)组成

段页式结构中各段的分页对用户是不可见的,用户只要关心段号和段内地址,段页式管理的地址结构是二维的

每个段对应一个段表,每个段表项由段号,页表长度,页表存放块号(页表起始地址)组成(本质上还是一堆页号与块号的映射)。

段页式管理方式中逻辑地址和实际地址的转化

根据逻辑地址获取段号,页号和页内偏移量(本质上还是段内偏移量,页是对段内偏移量的细分),之后根据段表寄存器中的段表始址和段表长度判断是否越界,若没有越界则查询段表(第一次访存)获取到段表项,然后根据段表项找到页表存放块号,并检查页号长度是否越界,若没有越界则读出页表,根据页表存放块和页号查询页表(第二次访存),找到对应页表项,最后根据内存块号和页内偏移量得到最终的物理地址并访问(第三次访存)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值