os之内存管理
推建清华大学陈渝老师讲的OS的课程。操作系统原理
介绍
从os角度来理解内存就是由装着0或者1的小容器(这些0,1数字就是暂时放在CPU内部的运算数据)组成的大容器,它是外存和CPU沟通的桥梁。当计算机运行的时候,os就会将需要运算的数据从内存调到CPU进行运算,运算完成,CPU将结果传送出来。
物理地址空间:硬件支持的地址空间,像硬盘,内存条
逻辑地址空间:一个运行的程序所拥有的内存范围
为什么要进行内存管理
笼统的说就是为了高效的利用资源。
连续内存分配
内存碎片
内存碎片就是指空间内存没有被充分利用
- 内部碎片:在分配单元中的未使用内存,已经分配给应用程序了,但是程序还有部分空间未使用。
- 外部碎片:在分配单元间未使用的内存。剩余空间未给程序分配。
动态分区
一种内存管理技术,分区是动态创建的,因此每个进程可以装入和自身大小正好相等的分区中,所以没有内部碎片,但是最终会在内存中形成许多小空洞,也就是所谓的外部碎片。
如何巧妙的将进程分配到内存,以克服外部碎片的问题?
有四种分配策略,各种策略的好坏取决发生进程交换的次序和这些进程的大小。
- 最佳适配:选择和要求大小最近的块。尽管每次都浪费最小的存储空间,但是会形成许多没用的微小碎片,通常这种方法是最差的。
- 首次适配:从头开始扫描内存,选择大小足够的第一个可用块。简单并且快速,但是内存的前端会出现很多小的空闲分区,而且每次进行首次适配,都要经过这些分区。
- 最差适配:选择和要求大小最不接近的块。
- 下次适配:从上一次放置的位置开始扫描内存,选择下一个足够的可用块。
连续内存分配的缺点
- 分配给一个程序的物理内存是连续的
- 内存利用率低
- 有碎片问题
非连续内存分配
分段技术
有几个需要熟记的点:
- 是对进行分段,分段的大小是可变的,一个段就是一个内存块
- 调用一个进程,所有段都要装入内存中的可用区域,同时建立一个段表
- 逻辑地址组成:段号+段内偏移(段在内存中的起始地址和段的长度)
- 段表:存储的是逻辑地址和物理地址的映射关系。包括进程中每一个段在内存中的起始地址(基址),段长度限制。
分段地址转换过程
参照清华大学陈老师的PPT,PPT好像有点错误。。不过不耽误理解地址转换过程。
- 首先运行的程序要通过CPU来执行指令,CPU要去寻址,把程序的逻辑地址分为段号和偏移两部分。
- 通过段号在段表中找到该段的起始物理地址。
- 偏移量和段长度比较,如果偏移量大于段长度,则该地址无效
- 物理地址就是该段的起始物理地址和偏移量之和。
分页技术
有几个需要熟记的点:
页:划分逻辑地址空间为相同大小的页,大小是2的幂
帧:划分物理内存至固定大小的页,大小是2的幂
- 分页技术页和帧的大小是固定不变的
- 帧:包括帧号和帧内偏移
- 页:包括页号和页内偏移,页内偏移的大小=帧内偏移的大小
- 页表:同样保存了逻辑地址和物理地址之间的映射关系,保存了以页号为索引的对应的帧号,页表项还有三个标志位。
- 逻辑地址空间和物理地址空间是不相等的,逻辑地址空间一般都大于物理地址空间
分页地址转换过程
参照清华大学陈瑜老师的PPT,
三个标志位:
- dirty bit(脏位):表示页面被带入内存后是否被修改过。
- resident bit(有效位):表示对应的帧在物理内存中是否存在,如果不存在表示异常。
- reference bit(访问位):用于追踪页是否被访问,也用于确定哪些页很受欢迎。
- 首先运行的程序要通过CPU来执行指令,CPU要去寻址,把程序的逻辑地址分为页号和页偏移两部分
- 然后根据页号在页表中找到对应的帧号,根据页帧号计算出物理地址
- 由于他们的页/帧内偏移相等,所以页表不用保存这个数据,但是页表有一些标志位。
分页机制存在的问题
- 访问一次内存单元需要两次内存访问:一次用于获取页表项,一次用于访问数据(设置缓存-快表)
- 页表占的内存很大(间接访问方式-多级页表)
快表
通过快表来优化页表的时间开销问题,TLB实际上是CPU的MMU内存管理单元保存的一段缓存,这段缓存保存的内容是经常访问到的那部分页表,其他不常用的页表内容保存在内存中。
这时候的地址转换过程
- CPU将逻辑地址分为页号和页偏移之后会先去快表中找对应的物理页号,没找到的话就会去访问页表,然后将页表中这部分再添加到TLB中。
多级页表(二级页表为例)
缓解分页机制页表占用的空间大的问题,但是这样做可能会增加内存访问次数和开销,但是节省了保存页表的空间,因为某些不存在映射关系的页表项不用占内存了,然后再通过快表来减少时间消耗。
如图所示,现在逻辑地址转换物理地址的过程变成了
- 逻辑地址中页号分为两部分,p1和p2。p1存着二级页表的起始地址,p2的作用就是之前的p,
- p1里面找二级页表,P2里面找页,o找地址,(如果p1某个页表项不存在的话,页表标志位为0,对应的二级页表就不用放了,这样也就是节省了内存)。
虚拟内存
产生
内存不够用了,程序规模的增长速度远远大于存储器容量的增长速度,这时候就考虑利用硬盘的空间,将硬盘的部分空间扮演内存的作用。将不常用的程序放在硬盘里,常用的放在内存上。在虚拟内存产生之前还有两种技术来解决内存不够用的情况。
覆盖技术
目标:在较小的可用内存中运行较大的程序,所谓覆盖其实就是使得某些程序模块公用一个内存分区。
- 需要程序员将程序按照自身的逻辑结构划分为几个功能独立的块,将那些不会同时执行的模块共享同一块内存区域
- 常用的代码和数据放在内存,不常用的平时放在外存,需要的时候装入内存
- 这样,不存在调用关系的模块不必同时装入内存,从而可以相互覆盖,使得某些模块公用一个分区。
交换技术
目标:让正在运行的程序或者需要运行的程序获取更多的内存资源,所谓交换就是内存中的程序和外存中的程序进行交换,只不过这种交换是以内存中的程序大小为单位来进行的。交换是发生在内存中程序和OS之间,而覆盖只在程序内部发生。
- 将暂时不能运行的程序送到外存(如何送),从而获得空闲内存空间
- OS将一个进程的整个地址空间的内容保存到外存中(换出),将外存中的某个进程的地址空间读入到内存中(换入)。换入换出是换的整个程序的地址空间。
虚拟技术定义
虚拟技术的目标
解决覆盖技术给程序员造成的负担和交换技术处理器开销大的问题
- 像覆盖技术一样,把常用的程序放入内存,因此可以运行比当前的内存空间大的程序,但是是OS完成
- 像交换技术一样,可以实现内存和外存之间的交换,而且是对进程的部分内容在外存和内存之间进行交换。
程序局部性原理
所谓局部就是当前和当前邻近的的操作,从时间和空间上来看,都会集中在一个较短的时间内和一个较小的区域内。就是程序在执行过程中的一个较短时间,所执行的指令地址和指令的操作数地址分别局限于一定区域。
通过程序的局部性原理表明,虚拟存储技术是可以实现的并且会取得满意的结果。
虚存技术的概念
也是虚拟页式管理的基本思路。
- 首先是在内存中装入程序时,不必将其全部装入内存中,只需要将当前需要执行的页面或者段装入内存中,就可以让程序执行
- 然后当程序执行的时候,如果需要执行的指令或者访问的数据不在内存(缺页或者缺段),则由处理器通知操作系统将外存中相应的页面或段调入到内存,然后继续执行程序
- 另一方面,OS会将内存中暂时不用的页面或段调出内存保存在外存中,从而腾出更多的空闲空间存放要装入的程序。
虚存技术的基本特征
- 大的用户空间:通过将物理内存和外存相结合的方式使得提供给用户大于实际物理内存空间的虚拟内存空间
- 部分交换:对比交换技术,虚拟存储的换入和换出是对部分地址空间进行的
- 不连续性:物理内存分配和虚拟地址空间的使用都不连续
虚拟页式内存管理
其实就是在页式存储管理的基础上增加了请求调页和页面置换的功能。
页表项的内容要熟记:
缺页中断的处理
处理页面,就要一个路径上包括页表都给处理了。
- 先看内存中是否有空闲的物理页面,如果有的话则分配物理页帧f,然后将需要访问的页p装入到物理页面f中,接着要反过来修改p对应的页表项内容,把页表项中的驻留位设置1,对应物理帧号设为f,重新运行被中断的指令。
- 如果内存中已经满了,没有空闲的位置了,就会采用一种页面置换算法,选择一个要被替换的物理页面f和对应的逻辑页面q。如果该页在内存期间被修改过,就需要将它写回外存。然后将q对应的页表项对应修改,将驻留位置设置为0.之后就是和内存中有空闲物理页面一样了。
页面置换算法
首先,要知道为什么有页面置换算法。当发生缺页中断的时候,缺页中断就是CPU要访问的页面不在物理内存中,CPU要从外存中将需要访问的页面给调入物理内存,如果此时物理内存还有空间就直接调入就行,但是如果此时物理内存已满,就必须将物理内存中的页面换出去一个,至于换出去哪个,从不同的角度考虑有以下几种不同的算法,但是目标是尽可能的减少页面的换进换出次数。
- 最佳页面置换算法:置换在将来最长时间不需要的页面。这种算法要求os知道内存中的每一个逻辑页面在下一次访问它之前,它需要等待多长时间,一一比较所有页面的等待时间,从中选出等待时间最长的那个。但是OS没法知道每一个页面需要等待多长时间以后才能再次被访问。是个理想的情况,但是是其他算法对比的指标。
- 先进先出(FIFO):置换在内存中驻留时间最长的页面。OS维护者一个链表,记录了内存中的逻辑页面,排列顺序就是根据页面的驻留时间来的,性能较差,调出的页面有可能是经常需要访问的页面,而且还有belady现象。(FIFO是从页面进入内存的时间来考虑的,但是不一定是进程不会 访问的,就导致了即使分配的物理页面增加,缺页率反而提高的异常现象。)
- 最近最少使用(LRU)页面置换算法:置换最久未使用的那个页面。LRU算法基于这样一个假设:在最近一段时间内,如果某些页面被频繁的访问,那在将来的一小段时间内,他们还可能被再次访问。反过来说就是如果某些页面 在长时间未访问,那他们在将来很可能长时间得不到访问。哈希链表来实现。(从页面的最近访问时间考虑的)
- 时钟页面置换算法:置换访问位为0的页面。当一个页面被装入内存时,将访问位初始化为0,如果这个页面被访问,就将这个页面初始化为1.所有的页面保存在 一个环形链表中,一个 表针指向最老的页面,当发生一个缺页中断时,算法先检查指针指向的页面,如果它指向页面的访问位为0就淘汰该页面,将新的页面插入这个位置,然后将表针前移一个位置,若访问位为1,就将该位置为0,然后指针向下移动一格,继续寻找下一个访问位为0的页面。
- 最不常用算法:置换访问次数最少的页面。每个页面设置一个访问计时器,当一个页面被访问就加一,发生缺页时,置换数值最小的那个。