操作系统之存储管理_2019-11-20

眉间皱痕 提交于 2019-12-05 05:36:50

存储管理

 早期计算机编程并不需要过多的存储管理

 随着计算机和程序越来越复杂,存储管理成为必要

 在存储管理中分为连续存储和非连续存储,非连续存储又分为分页存储、分段存储和段页式存储。

 

 存储管理的目的:

  确保计算机有足够的内存处理数据

  确保程序可以从可用内存中获取一部分内存使用

  确保程序可以归还使用后的内存以供其他程序使用

 内存分配与回收

  内存分配的过程

   单一连续分配:

    把内存分为系统区(被系统所使用)和用户区

    只能在单用户、单进程的操作系统中使用

 

   固定分区分配:

    内存空间被划分为若干固定大小的区域,每个分区只提供给一个程序使用,互不干扰

    支持多道程序的最简单存储分配方式

   动态分区分配(最常用的内存分配方法):

    根据进程实际需要,动态分配内存空间

    相关数据结构(计算机存储、组织数据的方式):

     (1)动态分区空闲表数据结构

       存储使用情况,是否被使用,是否容量足够

       
     (2)动态分区空闲链数据结构

       把所有的空闲节点首尾相连,形成一个双向链表

       可以把连续的空闲区合并为一个节点来减少节点数量

       

    动态分区相关分配算法:

     首次适应算法(FF算法):

      主要使用空闲链数据结构,从头部节点开始适配,直到找到容量大小能够满足需求的空闲区

      每次从头部开始,使得头部地址空间不断被划分,若头部都已被分配,就需要查找十分靠后的节点才能找到合适的内存

      为了改进这种情况,出现了循环适应算法,每次都从上一次检索结束的位置开始查找。

     最佳适应算法(BF算法):

      最佳适应算法要求空闲区链表按照容量大小排序

      遍历空闲区链表找到最佳合适空闲区,从小到大的遍历,可以减少碎片的产生,避免大材小用。 

     快速适应算法(QF算法):

      快速适应算法要求有多个空闲区链表

      每个空闲区链表存储一种容量的空闲区,效率比BF算法更高,可以快速找到适合的内存区域。

      

  内存回收的过程

   针对四种不同的情况,有四种回收的方式。 

   

 

     情况①             情况②            情况③             情况④

   情况①:

    不需要新建空闲链表节点

    只需要把空闲区1的容量增大为空闲区即可 

   情况②:

    将回收区与空闲区合并

    新的空闲区使用回收区的地址 

   情况③:

    将空闲区1、空闲区2和回收区合并

    新的空闲区使用空闲区1的地址 

   情况④:

    为回收区创建新的空闲节点

    插入到相应的空闲区链表中去

 段页式存储管理

  操作系统管理进程的空间,一般进程的空间在没映射到物理内存时,是在虚拟内存既是辅存中的。

  页式存储管理

   字块:相对物理设备(物理内存)的定义,一群字作为一个单元来处理的称为“字块”
 
   页面:相对逻辑空间的定义
 

   管理过程:

    将进程逻辑空间等分成若干大小的页面,相应的把物理内存空间分成与页面大小的物理块

    以页面为单位把进程空间装进物理内存中分散的物理块,把进程空间中的每个逻辑页面放到内存中的物理块里去

 

   内存碎片:

    进程空间中页面大小小于物理内存空闲区的大小,造成存在一段无法使用也无法回收的内存区域。

    页面大小应该适中,过大难以分配,过小内存碎片过,多页面大小通常是512B~8K。

 

    

 

   

   页表:

    记录进程逻辑空间与物理空间的映射的表,因为进程的逻辑空间分为的页

    面分散在主存不同的分散的物理块中,所以需要页表来记录。

    页表中有多少个页面就有多少个页表项。

    

    逻辑地址结构:

    由页号P和页内偏移量W(页内地址)两部分组成

 

    相关公式:

     逻辑地址A = 逻辑地址的页号P * 页面大小L + 偏移量W(“页内地址”又叫“页内偏移”)

     物理地址A = 某程序指定页的块号B * 页面大小L + 偏移量W

     偏移量W   = 逻辑地址A - 页号P * 页面大小L    = 逻辑地址A %(mod) 页面大小L 

 

    已知逻辑地址求物理地址:

     第一步 : 逻辑地址A / 页面大小L = 逻辑地址的页号P (整除)(商)

     第二步 : 逻辑地址A %(mod) 页面大小L = 逻辑地址的页内偏移量W(取余)

     第三步 : 生成页表,找出逻辑地址的页面所对应的页框号,一一对应,页号对应块号,从小到大排序。

         在实际中,由于虚拟内存一般都会大于实际的内存,所以页面的数量一般会大于或等于字块的数量。

      如:

       

 

      第四步:求出 物理地址 = 某程序指定页的块号 * 页面大小 + 偏移量W

 

   多级页表:

    https://blog.csdn.net/forDreamYue/article/details/78887035 多级页表就比一级页表要省空间?

    为了解决页表过于占用内存空间而出现的,

    由于现代计算机内存较大,可以存在非常多的页面,则页表项会十分的庞大,一个32位的系统,

    若规定页面为4KB,则会有2^20个页表项,若每个页表项占用1byte,每个进程仅仅页表就要占

    用1M的内存空间,而且每个页表都将会有所有的页表项来对物理内存空间进行映射。如果是在64

    位地址的计算机的情况下,如果按照相同的计算方法,一个进程的页表占用的空间一个普通内存根本

    放不下。关键是,一个进程,真的会需要一整个虚拟地址空间去存放吗?

    解决问题的核心在于,避免把全部页表一直保存在内存中是多级页表的关键所在。特别是那些不需要的页表就不应该保留。

 

    工作原理:

     根页表中,每个字块所指向的地址为内存中的一片空间,这一片空间存储的是二级的页表,假设每个

     二级页表有1024项,每一项指向的字块才是内存实际使用的内存。每个根页表可以指向多个二级页表。

     通过一个顶级页表为真正有用的页表提供索引。

     

  段式存储管理

   可以解决也是存储管理中的有一段连续的逻辑分布在多个页面中,在使用时将会大大降低执行效率的问题

 

   与页式存储管理的异同:  

    段式存储和页式存储都离散地管理了进程的逻辑空间

    页是物理单位,段是逻辑单位;

    分页是为了合理利用空间,分段是满足用户要求

    页大小由硬件固定,段长度可动态变化

    页表信息是一维(字块号)的,段表信息是二维(基址和段长)的

 

   实现:

    将进程逻辑空间划分成若干段(非等分

    段的长度由连续逻辑的长度决定,如:主函数MAIN、子程序段X、子函数Y等 

 

   段表:

    

  段页式存储管理

   分页可以有效提高内存利用率(虽然说存在页内碎片);

   分段可以更好满足用户需求,逻辑是用户写的;

   两者结合,形成段页式存储管理。

 

   实现:

    先将逻辑空间按段式管理分成若干段

    再把段内空间按页式管理等分成若干

    

    

  虚拟内存  

   虚拟内存实际是对物理内存的补充,速度接近于内存,成本接近于辅存。

 

   程序的局部性原理:

    局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个

    较小的连续区域中;

    根据此原理,程序运行时,无需全部装入内存,装载部分即可,如果访问页不在内存,则发出缺页中断,发起页面置换

    从用户层面看,程序拥有很大的空间,即是虚拟内存。

 

   使用虚拟内存的背景:

    ① 有些进程实际需要的内存很大,超过物理内存的容量;多道程序设计,使得每个进程可用物理内存更加稀缺

    不可能无限增加物理内存,物理内存总有不够的时候。

    ② 虚拟内存是操作系统内存管理的关键技术;使得多道程序运行和大程序运行成为现实;把程序使用内存划分,

    可以将部分暂时不使用的内存放置在辅存,只需把要使用的(红色)加载到物理内存中,

    如下:

     

   虚拟内存的置换算法  

    替换策略发生在Cache-主存层次、主存-辅存层次

    Cache-主存层次的替换策略主要是为了解决速度问题

    主存-辅存层次主要是为了解决容量问题,一般虚拟内存的置换指的是这个层次。

 

    主存页面的替换时机:

     

 

    高速缓存的替换时机:

      

  Linux的存储管理

   内存碎片:

    页内碎片:

     内部碎片是已经被分配出去(能明确指出属于哪个进程)的内存空间大于请求所需的内存空间,不能被利用的

     内存空间就是内部碎片。 空闲区容量大于页面大小,则造成业内碎片。

     

 

    页外碎片:

     外部碎片是指还没有分配出去(不属于任何进程),但是由于大小而无法分配给申请内存空间的新进程的内存空闲块。

     操作系统在不断分配空闲区,会根据进程的需要来分配不同的内存空间给进程使用,会造成一些较小的空闲区由于过小而

     无法被继续分配,造成页外碎片。

     

   Buddy(伙伴)内存管理算法

    Buddy算法是经典的内存管理算法,一种实际在内存中运行的一种内存管理算法,

    基于计算机处理二进制的优势具有极高的效率,主要是为了解决内存外碎片的问题,

    可以把内存外碎片问题转变为内存内碎片问题,把内存按2的幂次方大小来分配,可以避免出现内存外碎片。

    目的是努力让内存分配和相邻内存合并能快速进行。

 

    伙伴系统:

     “伙伴”指的是内存的“伙伴”;

     一片连续内存的“伙伴”是相邻的另一片大小一样的连续内存。

     

 

    Buddy实现:

     Buddy内存分配原则:      

      在每次分配内存时,都是默认向上取整为2的幂的大小

      如:

       70k→128k

       129k→256k

       666k→1024k

     实现过程:

      创建一系列空闲块链表,每一种都是2的幂,如容量大小为2^1=1的为一条双向链表,2^2、2^3 ... 以此类推。

      

      例子:

      假设存储空间有1M大小(为1M的空闲链表中有一个节点),按Buddy算法分配100k内存,这组空闲链中情形如下图:

       

      1. 100k向上取2的幂=128k

      2. 查询是否存在大小为128k的空闲内存块(看看表示128KB空闲区的链表上有没有节点)?

      3. 没有!查询是否有256k空闲内存块?

      4. 没有!查询是否有512k空闲内存块? 

      5. 没有!查询是否有1M空闲内存块?

      6. 有,摘下1M空闲内存块,分配出去 

      7. 拆下512k放在512k的空闲链表(由1M=2^10降幂1,得512KB *2,未得到所需的128KB),其余的分配出去 

      8. 拆下256k放在256k的空闲链表,其余的分配出去

      9. 拆下128k放在128k的空闲链表,其余的分配出去

      10. 分配完毕(最小只能分配给128KB大小的空闲区,若无则分配更大的空闲区供使用)

      

   Linux交换空间

    交换空间(Swap)是磁盘的一个分区, Linux物理内存满时,会把一些内存交换至Swap空间,但是交换空间在磁盘,速度较慢。

    Swap空间是初始化系统时配置的。

     冷启动内存依赖,很多大型的应用程序,在启动时需要使用大量的内存,但是这些内存在启动后就很少会被使用,可把

     这部分置换到交换空间里,以释放更多的物理内存给系统使用。

     系统睡眠依赖,当linux需要睡眠时,会把内存中所有的数据保存到swap空间里,下次启动时才重新加载到内存中,这样

     可以加快系统的启动速度。

     大进程空间依赖,对于一个应用确实需要使用十分大的物理内存空间,当物理内存不足时,把进程需要使用的内容暂时保存

     到swap交换空间中。

 

    与虚拟内存对比:

    

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!