阅读:4171回复:0
【操作系统】之内存管理
内存管理的主要功能:
1)内存空间的分配与回收 2)地址转换(逻辑地址与物理地址) 3)内存空间的扩充(利用虚拟技术) 4)内存保护(保证作业互不干扰) ======================================================================= 一. 进程运行的原理 ======================================================================= 编译 ------> 链接 ------> 装入 编译(由编译程序将用户源代码转换为若干目标模块),链接(由链接程序将编译后形成的一组目标模块以及所需要库函数链接到一起),最后装入,将整个装入模块装入内存。接下来详细介绍这三个步骤。 链接:程序链接就是将编译好的目标模块链接上必要的库函数。有三种链接方式: 1、静态链接:在装入内存之前把所有需要的库函数链接成一个完整的可执行程序,以后将不再打开。 2、装入时动态链接:将用户编译好的模块直接装入内存,采用边装入边链接的方式。 3、运行时动态装入(最佳):对某些大型的软件,所需要的库函数比较多,但是并不是每个模块都用得到。所以采用,在用这个模块的时候再链接上库函数。 装入:装入内存也有三种不同的方法 1、绝对装入,实际地址是代码中直接给出的,是固定的,也是静态的。所有很简单直接按照地址装入就行。只适合单道程序的环境。 2、可重定位装入,在多道程序环境下,多个目标模块的起始地址通常都是从0开始的,所以我们把0开始的地址叫作逻辑地址,这就需要重新定位转换成物理地址,才能把程序放到合适的内存空间中。此种方法也称为静态重定位,一次必须分配足够程序运行的内存空间。并且在整个运行过程中,不能移动地址。 3、动态运行时装入(动态重定位),相比于静态重定位,在装入后,并不转换逻辑地址为物理地址,而是在需要执行的时候,才转换。因此装入内存后的地址依旧是逻辑地址。这种方式需要一个重定位寄存器来记录如何转换成物理地址。通过这种方法,程序可以分配到不连续的存储区间,可以使用逻辑上更大地址空间。程序在初次创建的时候只申请一部分内存空间,根据需要动态申请分配内存。 逻辑地址和物理地址 逻辑地址是操作系统上层的程序使用的地址,物理地址是计算机中内存的地址。而中间就是操作系统,操作系统负责转换地址。这样不仅可以方便用户和应用程序猿,并且可以通过虚拟技术使用更大的逻辑地址空间。而对于操作系统,就负责转换这些地址,从逻辑地址转换到物理地址的过程就是重定位。 ======================================================================= 二. 内存保护 ======================================================================= 内存保护有两层意思1、操作系统不能被用户进程影响(保护操作系统)2、用户进程之间不能互相影响。 有两种办法: 1)简单办法:设置一对上下限寄存器,每次运行前要判断有没有越界。(虽然简单,但是地址必须是连续的) 2)使用重定位寄存器和界地址寄存器来实现这种内存保护。重定位地址的功能是用来转换逻辑地址的,因为地址在物理上可能不连续,所以我们在逻辑地址上来判断有无越界。如果判断通过,则通过界地址寄存器转换为物理地址。 ======================================================================= 三. 覆盖与交换(用来扩充内存的技术) ======================================================================= 覆盖已经过时是交换技术的过渡版本。 交换(对换):交换的基本思想就是把内存中的暂时在等待状态的进程从内存中调到辅存中去。把内存空间腾出来叫换出,再把准备好竞争cpu资源的进程放进内存,这叫换入。 交换需要注意以下几个问题: 1、交换需要备份存储。 2、为了有效使用cpu,运行时间要比交换时间长的多 3、如果换出进程,必须保证进程是空闲的。 4、交换所用的空间是磁盘的一块,是独立于文件系统的。 5、交换通常用于在有许多进程运行且内存空间不够的时候使用。 6、普通的交换使用并不多,但是此种方法的变种很多。、 ps:现代操作系统主要是使用虚拟内存的方式来解决内存不足的问题。 ======================================================================= 四. 两种内存分配管理方式 ======================================================================= 一、连续分配管理方式 --------------------------------------------------------- 连续分配就是为一个用户进程分配一个连续的内存空间,有三种具体的方式。 1)单一连续分配(适合于单道程序系统) 2)固定分区分配 内存空间分区,可以是大小相等的,也可以是大小不等的 每个区都或多或少有冗余(内部碎片)。存储器利用率很低 一种最简单的多任务处理的内存分配方式,但是效率不行 3)动态分区分配 顾名思义,这是一种分区大小可变的内存分配方式 系统会给分配给进程大小完全合适的一个区,就避免了内部碎片。动态分区一开始的时候,效率很高,但是随着时间的推移,内存利用率开始变低, 外部碎片增多,内存的利用率就会降低。 解决外部碎片可以使用紧凑的方法,就是隔一段时间,移动一下,但是非常的费时的。 因此,要想动态分区分配的方法可以更好的使用,就需要思考,以怎样的算法来分配内存空间可以减少外部碎片的冗余那。有四种分配方式: 1、首次适应算法:简单粗暴,分配内存的时候,顺序查找,找到第一个能用的空间,就用。 2、最佳适应算法:空闲分区按容量递增的方式排号,进程找到一个最小的能满足自己的空闲分区。 3、最坏适应算法:空闲分区按容量递减的方式排号,进程找到一个最大的能满足自己的空闲分区。 4、邻近适应算法:也称循环首次适应算法,是首次适应算法的增强版,不再每次都从头开始查找,而是从上次分配的地方开始。 性能分析: (首次>最佳)>最坏 邻近适应算法尝试解决,但是失败了,性能很差。 最佳适应算法产生最多的外部碎片。 总体上,反而是最简单的首次是最好的。 二、非连续分配管理方式 --------------------------------------------------------- 非连续的方式允许同一进程分布在不连续的内存空间中。相比于连续的方式,可以让需要更大内存空间的进程运行。但是由于需要索引表连接不连续的空间,所以存储密度是低于连续的方式的(就像数组和链表的区别)。同样,非连续的分配管理方式也有三种方式: -------------------------------- 2.1)基本分页管理方式 -------------------------------- 首先把内存空间分割成大小相等的块,作为主存的最基本的单位。这里的块在不同的情况有不同的名字。进程中的块,即使用中的块,称为页。而内存中的块,即没有使用的块,称为页框。外存中的块就叫块。 连续分配方式中的固定分区,是整体,是可以装进整个进程的大小的单位。而这里的块是相对小很多的,是组成进程的大小单位。这其中的区别是非常大的。 1、分页分配方式的地址格式 地址结构主要由页号和页内偏移量组成。首先要明白,地址是什么的地址,这里的地址是内存空间中的字节的地址。那么该如何用这两个信息来表示字节的地址那?页号就是块的编号,内存中的所有的块有一个唯一的快号。这里的页号是可以通过下文中的页表的形式来转换为唯一额块号的。有了页号就能找到那个唯一的块。然后页内偏移量就是块内部字节的编号了,从头开始往后,就能通过这个地址找到唯一的字节了。在说什么是页表之前,首先要明白,什么是页号什么是块号,为什么两者要进行转换?页号就相当于逻辑地址,而块号就相当于物理地址,所以需要页表来进行转换。页表中会存放着页号和块号对应的关系。 2、基本地址变换机构(重点) 即各种号是如何计算的,以及如何转换的。 在系统中要有一个页表寄存器,存放着页表的起始地址F和页表长度M。在进程运行之前,这两个信息还在PCB中,运行时放入页表寄存器。页面大小为L,那么逻辑地址A和物理地址E的转换过程就是这样的。 (1)分别计算出页号和页内偏移量 页号=逻辑地址/页面长度 页内偏移量=逻辑地址%页面长度 (2)比较页号和页表长度,若页号大于页表长度,说明越界,则中断。 (3)页表项地址=页表起始地址+页号*页表项长度,计算出页表项地址后,取出地址中的内容,这个内容就是块号。 (4)计算物理地址=块号*页面大小+业内偏移量,则得到物理地址 3、快表 页式管理的主要问题:地址转换必须很快,否则会降低速度。另一个问题就是页表不能太大,否则内存利用率就会很低。为了提高业式管理的效率,故引入快表。顾名思义,快表就是很快的页表。快表就是将部分正在用的页表放进cache中,以达到更快的速度。所以放在内存中的页表就叫做慢表。这样,带有快表的地址变换就成为,cpu给出的逻辑地址,硬件计算出页号后是给cache的,通过cache计算出物理地址,然后去访存,所以只需要一次访存。快表的命中率可以达到90%左右,这样可以有效的降低分页式寻址上的时间损耗。 4、两级页表 实际上二级页表就是建造页表的页表。为了提高效率,最高级的页表只能有一页,这样就可以快很多,我们把顶级页表放在cache中。那么逻辑地址的格式就会变为,一级页号、二级页号、页内偏移。 -------------------------------- 2.2)基本分段管理方式 -------------------------------- 设计原因是页的不足,页是对于计算机的角度设计的,人是很难使用的,因为页没有逻辑,只有页号,一个进程,一段代码,我们只能用那几页来表示。不同的东西,却没办法通过页形成为跟别。所以我们设计了一种以逻辑段为单位的分段管理方式。 1、分段,把进程的各个部分按照功能不同分段,比如数据段,代码段,堆栈段。然后每个段分配一段连续的空间,段内连续,段间不连续。其逻辑地址由段号和段内偏移量组成。 2、段表,段表中记录着段表项在内存中的地址。段表内容为段号、段长、本段在内存中的起始地址。这样就可以通过查询段表来找到段内信息的物理地址。 3、地址转换,同样的设置一个段表寄存器,存着段表起始地址和段表长度,这里的段表长度的单位是段,表示的是几个段,那么段号就不能大于段长。依旧是通过段表的起始地址加上段号*段表项长度得到我们段表中的信息,获得段起始地址后,我们就可以通过段内偏移量得到物理地址。 【缺点】页式可以提高效率,但是没有逻辑性,段具有逻辑性,但是缺乏效率。 【ps】段和页的内存保护主要是通过限制存取和地址越界保护来实现的。 -------------------------------- 2.3)段页式管理方式 -------------------------------- 为了既有页的优点,又有段的优点,就有了段页式管理方式。既然结合了这两种方法,我们就在重新梳理一下对内存是如何改造成现在这幅模样的。 首先我们的内存是以字节为单位的,内存最大地址其实就是字节数目。因为字节太小了,所以我们有了页式管理,把块分成单位更大的页,让我们更便于管理。但是页又缺乏逻辑性,让我们人类很难直接使用,因为其本质不过是大一点的字节罢了,太底层了,人很难使用。所以我们设计了段这样的单位,那么什么是段页的结合那?就是段式管理中,段的长度是多少个字节,现在段下面的单位变成页了,即段的长度变为几页了。 在段页式管理中,为了进行地址变换,我们设置了一个段表和若干个页表,随之而变换的字节的逻辑地址格式变为段号、页号、页内偏移量。在进行地址变换中,通过段表查找到页表起始地址,然后通过页表找出块号,找到物理地址。所以段页式进行一次访问要3次访存,一次段表,一次页表,一次真实内容。所以我们依旧可以使用快表,来减少访存次数。 【总结】非连续的方式,就像数据结构中链表,而连续的方式就像数组一样。两者各有优缺点。段页也不过是通过不同的角度将内存空间分层,更加易于管理。 参考:https://blog.csdn.net/qq_37747664/article/details/82381860 |
|