熟悉完操作系统的第二篇章,开始学习第三篇章,关于操作系统的内存管理。

0猜你喜欢

操作系统系列文章

操作系统学习笔记 1概述

操作系统学习笔记 2操作系统介绍

操作系统学习笔记 3内存管理

操作系统学习笔记 4非连续内存分配

操作系统学习笔记 5虚拟内存

操作系统学习笔记 6页面置换算法

操作系统学习笔记 7进程管理

操作系统学习笔记 8CPU调度

操作系统学习笔记 9同步&互斥

操作系统学习笔记 10信号量&管程

操作系统学习笔记 11死锁

操作系统学习笔记 12进程间通信

操作系统学习笔记 13文件系统

3内存管理

计算机启动后,通过BootLoader加载操作系统,让操作系统能够启动。操作系统加载到内存之后,会对计算机系统进行管理和控制。首先管理和控制的就是内存,这个篇章主要是操作系统如何管理物理内存。

主要内容

  • 计算机体系结构/内存分层体系
  • 地址空间 & 地址生成
  • 连续内存分配

3.1计算机体系结构及内存分层体系

3.1.1计算机体系结构/内存分层体系

  • 计算机体系结构
  • 内存分层体系
  • 在操作系统的内存管理范例

CPU主要完成了整个程序或者软件执行的控制,内存放置了程序的代码和处理数据,外设包括键盘鼠标等,不同外设有不同的作用,配合程序发挥更大的作用。比如把数据永远的保存到硬盘中。

3.1.2层次结构

操作系统需要在这个阶段把CPU访问物理内存有效地管理起来。内存包含的层次结构如下

从上到下CPU可访问的数据很多种类,比如寄存器,cache(高速缓存,一般现在的计算机都是三级缓存),主存和磁盘。

  • 寄存器和cache

    位于CPU内部,操作系统无法对这两种数据直接管理,它们属于有访问快但是容量小特性。放置的数据和指令是有限的。

  • 主存

    可以存储很多可以运行的程序,如果数据过大放不下需要将数据放到硬盘中,这就需要操作系统管理和控制。主存的数据属于一掉电数据就没了。需要在掉电前把数据放入硬盘中。

  • 磁盘

    掉电后,能够保存数据的类型。数据访问速度较慢,但是容量比较大。

可以发现越靠近CPU数据访问速度越快,容量越小,越到磁盘速度越慢,容量越大。数据访问速度越快,并且容量,需要操作系统去管理物理内存和虚拟内存,可以完成看起来不可能完成的任务。

3.1.3四个目标

操作系统需要完成的事情,有四个目标

抽象:不用考虑底层的细节,只需要访问连续的具体地址(逻辑地址空间)

保护:可以运行多不同应用程序,不同的应用程序可能会访问别的程序的地址空间,造成应用地址的破坏。有效的机制能够保护进程间的地址,使得地址在不同的应用程序间相互隔离。

共享:需要一个共享的空间,用于数据传递

虚拟化:在内存中放了很多应用程序,会出现内存不够的情况。正在运行的程序获取所需要的空间,可以采用最需要放到内存的数据放到内存中,暂时不需要的数据可放入硬盘中。

逻辑地址空间和物理地址空间

主存和硬盘属于物理地址空间,运行的程序属于逻辑地址空间

四个目标需要机制完成,机制包含了相关的手段

  1. 在操作系统中管理内存的不同方法

    程序重定位

    分段

    分页

    虚拟内存

    按需分页虚拟内存

  2. 实现高度依赖与硬件

    必须知道内存架构

    MMU(内存管理单元):硬件组件负责处理CPU的内存访问请求

3.2地址空间与地址生成

3.2.1地址空间 & 地址生成

地址空间定义

地址空间生成

地址安全检查

地址空间

  • 物理地址空间

    是和硬件直接对应,比如内存条所代表的的主存和硬盘所代表的的另一种存储空间。物理地址空间的控制和管理,是由硬件来完成的。

  • 逻辑地址空间

    一个运行的程序他所拥有的空间,一维线性的空间,应用程序会比较访问,相关的控制等。

所有运行的程序,它所访问的逻辑地址空间,最终都落在一个物理内存中。比如每条指令,根据逻辑地址空间,它位于箭头指向的程序所指的位置(上图所示),但最终会放置咋主存中或者硬件中。至于放在主存还是硬盘中是由操作系统协调的,可以明确的说明这种映射关系需要操作系统有效的管理。

3.2.2逻辑地址生成

通过编译期,通过linker,通过loader就可以完成这个过程的建立。

  • c程序通过编译可以把c程序,编译成汇编程序。c程序中,函数的名字,变量名字就是一种地址,是一种人容易理解的方式存在的
  • 汇编程序,更加接近机器语言,但还是符号代表变量和函数的名字,相对机器语言也更好地让人理解阅读。
  • 通过汇编器,可以转化成机器语言.o文件,起始地址都是从0开始,会把函数符号名、变量符号名转化为相应的地址
  • 大的程序是由多个小的程序组成的,可能使得不同的程序之间的地址相互访问。通过linker将这些.o文件最终变成单一的可执行文件exe file。exe file是一个单一的文件,可以在文件中执行暂时还存在硬盘中的程序。这个程序中地址已经做了一个全局的分布,不同的.o程序能够在单一的执行中有相应的定义,这个定义还不在内存中的一个位置
  • loader应用程序,让这个放在硬盘中的可执行程序放到内存中去运行。这一步会需要去完成把这个逻辑地址完成相应的分配,使得应用程序在内存中可以正常的跑。相对与执行程序,它会有相应的偏移量,偏移量可为0或者特定的偏移量。有了这个值,所有的程序都依照这个偏移量来正确的进行数据访问和指令的操作。从符号的逻辑地址到最终在内存中可以运行的具体的逻辑地址,这个过程有很多转换过程,这个过程不需要操作系统做任何帮助。

3.2.3这个指令所处的逻辑地址是怎么映射到物理地址上面去的

指令有自己的逻辑地址。需要把指令从内存中取出来,放在物理内存中的什么地方,这就有一个映射关系。

硬件中有MMU(内存管理单元)。MMU在有块区域表示这个映射关系(蓝色位置所示)。映射我们查表就可以知道,逻辑地址到物理地址的一个映射。逻辑地址和物理地址的关系,是需要通过操作系统完成的。

可以简化下面几个步骤

  1. CPU要执行某条指令的时候,它的ALU(计算逻辑单元)部件需要这条指令的内容,它会发出请求,发的请求带着参数就是逻辑地址。
  2. CPU的MMU会去查找逻辑地址的映射表,是否存在对应的物理地址,如果有的话就匹配。
  3. 如果没有的话就会从内存(主存)中找。如果找到了,CPU的控制器会给主存发起请求,需要一个物理地址的内容(指令的内容)。
  4. 主存会把内存的内容通过总线传给CPU,CPU拿到这条指令的内容就可以对它执行操作。

3.2.4地址安全检查

操作系统首先要确保每一个程序有效访问的地址空间。

第一部分是起始地址,第二个是长度。通过这两部分可以知道这个区域是这段程序的合理范围,超出区域的访问是这个程序不合法的访问。

一旦CPU去执行某条指令的时候,它会查询这个map。这个map会指出来,他访问的地址,逻辑地址是否满足区域的限制。然后找到对应的物理地址的位置,数据和指令取回来。一旦不满足,CPU就会产生memory异常(内存访问异常),

3.3连续内存分配

  • 内存碎片问题
  • 分区的动态分配(第一适配、最佳适配、最差适配)
  • 压缩式碎片整理和交换式碎片整理

3.3.1内存碎片问题

内存碎片问题就是空闲内存不能被利用

外部碎片:在分配单元间的未使用内存

内部碎片:在分配单元中的未使用内存

3.3.2连续分配内存:内存碎片与分区的动态分配

操作系统会对应的三种算法,分别是第一匹配分配、最佳匹配分配、最差匹配分配。

为了使得程序能够得到连续的区间,程序中的数据可以有连续的空间。

3.3.2.1第一匹配分配

为了分配n字节,使用第一个可用空闲块以致块的尺寸比n大。

3.3.2.2最佳匹配分配

为了分配n字节,使用最小的可用空闲块,以致块的尺寸比n大

3.3.2.3最差匹配分配

为了分配n字节,使用最大可用空闲块,以致块的尺寸比n大。

3.3.2.4总结

到底哪一种是做好的算法?其实没有最好的算法这一说。应用程序的请求是随机产生的,根据特定的场景产生有各自的特点,应用程序一会需要大的空间块,一会需要小的空间块,需求是随机的可变的,不存在一种可以满足所有的需求。

第一匹配分配 最佳匹配分配 最差匹配分配
基本原理 简单实现 1)为了避免分割大空间块2)为了最小化外部碎片产生的尺寸 为了避免有太多微小的碎片
需求 1)按地址排序的空闲块列表2)分配需要寻找一个合适的分区3)重分配需要检查,看是否自由分区能合并于相邻的空闲分区(若有) 1)按尺寸排列的空间块列表2)分配需要寻找一个合适的分区3)重分配需要搜索及合并于相邻的空间分区(若有) 1)按尺寸排列的空闲块列表2)分配很快(获得最大的分区)3)重分配需要合并于相邻的空闲分区,若有就调整空闲块列表
优势 简单,易于产生更大空闲块,向着地址空间的结尾 当大部分分配的尺寸是小尺寸时非常有效,比较简单 假如分配是中等尺寸效果最好
劣势 产生外部碎片和不确定性 产生外部碎片,重分配慢和易产生很多没用的微小碎片(不怎么样) 重分配慢,产生外部碎片和易于破碎大的空闲块以致大分区无法被分配

3.3.3连续分配内存:压缩式与交换式碎片整理

3.3.3.1压缩式碎片整理

  • 重置程序以合并孔洞
  • 要求所有程序是动态可重置的
图3-1 图3-1

这里面有四个程序,还剩余5个内存块。如果有第五个程序想占用这5个内存块,其实不能够满足需求,因为这5个内存块是不连续的。

目前可以采用挪动内存块的方式,如上图3-1右边所示,p2,p3,p4都往上去挪动,使得空间块能够空出来。这个过程也是内存拷贝的过程。

但其实这个过程不是单纯拷贝这个简单,还需要考虑何时重置和开销。程序在运行的时候显然不满足要求,可以在程序的停止过程,这个时候程序没有占用CPU执行,处于等待状态。另外开销问题,程序从一个地方拷贝到另一个地方,也许速度会很快,但是内存中频繁做这类操作,内存拷贝的开销也会增大,甚至会影响整个系统正常的执行。纯靠软件的话,存在很大的开销的问题。

3.3.3.2交换式碎片整理

另外,可以利用硬盘。可以把硬盘当做内存的后备。

这里P1,P2,P3应用程序正在等待运行,P3这个时候运行,且在P3应用执行过程中需要更多的内存,从3个内存块到6个内存块。而此时已经没有更多的内存,通过压缩式碎片整理的方法,已经不起作用。由于P1,P2,P4,已经把空间占满了,只能把硬盘当做备份(类似华容道原理)。P4占了3个内存块,由于P4正在等待某个事件,这个时候把P4占用挪到硬盘上去,3个空闲内存块正好可以让P3使用。P4数据并没有消失,只是从主存放到了硬盘上去。P4需要执行的时候,再从硬盘拷贝到主存中去。

但其实这个过程拷贝到硬盘中去,还需要考虑哪些程序交换和交换的时机。如果程序本身比较大,主存和硬盘的交换开销也是很大的。