OS内存管理
OS内存管理
一、内存管理(核心:逻辑地址和物理地址的映射)
操作系统内存管理的目标
-
逻辑地址:启动后,OS逻辑划分物理内存。用户程序在运行的时候,只考虑逻辑地址,不用考虑物理地址。
逻辑地址和物理地址的关系:CPU中ALU需要读取逻辑地址的内容,CPU中有个硬件MMU,MMU中有个地址映射关系表,负责转换逻辑地址和物理地址。CPU中的控制器把得到的物理地址和控制信号送到总线上,内存发送物理地址的内容给CPU。(操作系统做了什么等后面再补充)
-
保护:多个进程空间互不干扰
地址安全检测:用OS有个表,执行前检查起始地址+访问长度是否超范围。确保每个进程访问的地址空间合法。
-
共享:进程可以访问相同内存
-
虚拟化:更多的地址空间
-
虚拟内存:内存不够用,将磁盘用于虚拟内存。
在操作系统中管理内存的不同方法
-
重定位:链接后确定了代码相对地址,将程序.out载入内存,确定代码的逻辑地址。
-
分段:代码、数据、堆栈分开存储
-
分页:内存分成内存页4K,基础访问单位
-
虚拟内存:按需分页虚拟内存
1. 连续内存分配
连续内存分配所涉及的问题:
-
内存碎片问题:
- 空闲内存无法利用,包括分配单元之间的未被分配的空闲内存,以及被分配了但未使用的内存。
-
动态分区分配:
-
包括分配连续区间来加载未运行的程序,以及分配区间给已运行的程序
-
分配策略:
需要维护的数据结构:所有进程被分配的分区,空闲分区
- 最先匹配:找到第一个比要求的空间大的分区
- 最佳适配:找比要求的空间大的最少的分区,根据空闲分区大小排序
- 最差适配:找最大的,根据空闲分区大小排序
-
-
碎片整理:
- 调整进程占用的分区位置来减少或避免分区碎片
- 压缩:条件:只能在进程等待状态下搬运,内存拷贝的开销需要另外考虑。
- 交换式:把等待状态的进程放到虚拟内存上(硬盘),回收内存。
- 调整进程占用的分区位置来减少或避免分区碎片
2. 非连续内存分配
连续内存分配存在碎片问题,而且动态分配内存修改困难。
非连续分配的目标:提高内存利用效率和管理灵活性,比如允许程序使用非连续的物理地址空间,允许共享代码和数据,支持动态加载和动态链接。(多个程序引用同一个库,这个库只导入一次)
非连续需要解决的问题:
-
逻辑地址和物理地址之间的转换。
解决办法:软件实现(灵活、开销大),硬件实现(够用、开销小)
-
如何选择非连续分配中的内存分块大小
2.1. 段式
段式:分块大,要求每个段的段内物理地址连续,不同段可以放到不同的物理地址上
- 段地址空间
- 进程的段地址空间由多个段组成,分为主代码段、子模块代码段、公用库代码段、堆栈、堆数据、初始化数据、符号表等。段内用地址偏移访问,很少有段间访问。则连续的逻辑地址空间可以分为不连续的物理地址空间
- 段访问机制
- 逻辑地址由{ 段号+段内偏移 } 表示。访问过程:CPU根据逻辑地址,找到段号和段内偏移。在进程的段表中找到相应段号的段基址和长度。存储管理单元MMU判断是否越界(偏移<长度),然后根据段基址+偏移找到实际的物理地址。
2.2. 页式
页式:分块小,要求页内的物理地址连续,不同页可以放到其他地方
-
帧Frame{ 帧号+偏移量 }:把物理地址划分为大小相同的基本分配单位。
-
页Page{ 页号+偏移量 }:把逻辑地址划分为大小相同的基本分配单位。
Frame和Page的大小要求相同,偏移量要求相同,页号和帧号可以不同。
-
页表:{页号+帧号}:Frame和Page之间的转换关系。页表随进程运行动态变化。
访问过程:页表基址寄存器存放了页表的起始位置。CPU根据页号和偏移量,在在页表中找到对应的帧号,算出物理地址。页号可能没有对应的帧号,因此页表中还有标志位来表示映射关系是否存在。另外还有修改位和引用位,是否被修改,是否被访问。
缺点:访问一个内存单源需要两次访问,另外,如果内存很大,页表也会很大。
解决:
- (快表TLB)可以通过缓存页表项,减少访问次数
- (多级页表)对应逻辑地址,类似Page.x->Frame.y的映射。通过设置多级索引,减少页表存储空间。比如3级页表,逻辑地址用(p1,p2,p3,o)表示,p1指向第一级页表的页号,其中存放第二级页表的基址,p2指向第二季页表的页号,p2页号+基址=第三级页表的基址,p3页号+基址+偏移量o=物理地址位置。
- (页寄存器、反置页表):根据物理页号映射逻辑页号,类似Frame.y->Page.x的映射。大小只和物理地址大小有关,和逻辑地址大小无关。省空间,可用哈希表做,但会有哈希冲突,加入PID可以缓解冲突,把结果反哈希算一下是否相等即可。
2.3. 段页式
在段式存储管理基础上,给每个段加一级页表,逻辑地址= { 段号+页号+偏移量}
在寄存器中找到段基址+段号=段表项,其中有页表的基址。页基址+页号=页表项,其中由帧号的基址。帧号+偏移量=物理地址。优点:便于实现内存共享。共享段指向同一个页表,通过相同的页表基址,实现内存共享
二、虚拟存储
需求:进程并发量大,导致内存不够用。要求在小内存中运行大程序
解决:在非连续存储的基础上,将部分内存中的内容放入外存
覆盖:应用程序手动(得自己写)把需要的指令和数据保存在内存中。
交换:操作系统自动(操作系统写)把暂时不执行的程序保存到外存中
虚拟存储:以页为单位自动装入更多更大的程序
2.1 覆盖
问题:一个程序的内存空间不够用
覆盖:将程序划分为若干功能相对独立的模块,将不同时执行且大小相近的模块共享一块内存区域。
换入换出的基本单位:程序内部的模块
具体:将程序划分为必选和可选项,必选部分常驻内存,可选部分在用时放入内存。
缺点:编程难度增加
2.2 交换
问题:并发情况下,正在运行的程序内存不够用
交换:将暂时不运行的程序放到外存。
换入换出的基本单位:整个不运行的程序的地址空间
换出之后再换入需要采用动态地址映射。
2.3 虚拟存储
例子:二维数组有从上到下和从左到右两种遍历方式。如果是从上到下,且数组特别大,按页存储,在访问的过程中会N次缺页,处理效率大大降低!
虚拟存储的目标:只把部分程序放入内存,就让程序运行。且操作系统自动完成
装载时:只将当前指令执行需要的部分页面或段装入内存
缺页/缺段中断:执行中需要的指令或数据不存在内存中。CPU通知OS调入相应页/段
保存:将内存中不用的页/段放入外存。注意:应能方便找到在外存的页。Linux专门设置了对换分区。另一种是采用特殊格式的文件来存储
实现方式:
-
虚拟页式存储
在页式存储管理的基础上,增加请求调页和置换算法。页表项增加了几个标志位:驻留位:判断该页是否在内存中;修改位:判断当前页是否被修改过,若修改过,置换时需要将修改的内容放到外存中,否则置换时直接作废即可;访问位:判断当前页是否被访问过,不常用的页需要被放入外存中。保护位:表示该页允许的访问方式:rwx。
-
虚拟段式存储
2.4 页面置换算法
置换算法:缺页异常,需要调入新页而内存已满,就需要置换
要求:页面调入调出次数少,调出未来不用的页面(难点:如何估计?)
页面锁定:必须内容常驻内存,不可被置换
置换算法评价方法:记录进程访问内存的轨迹,模拟每种页面的置换行为,记录产生缺页的次数,越少性能越好
-
局部置换算法:分配给进程的物理页面数确定,置换只局限在该进程占用的物理页面内
- 最优算法:缺页时,计算内存中每个页的下一次访问时间,选择未来最长时间不访问的页面,但该算法无法实现,是用于评估置换算法。
- 先进先出FIFO:选择在内存驻留时间最长的页面进行置换
- 最近最久未使用算法LRU:选择最长时间没有被引用的页面
- 改进:时钟算法CLOCK:只做粗略统计,各个页面组成环形链表,指针指向最先调入的页面,环形查找,访问过的留下,没访问过的被置换。
- 改进:最不常用算法:每个页设置一个访问计数,访问时+1,缺页时,选择计数最小的页
-
全局置换算法:全局置换算法位进程分配可变数目的物理页,选择范围是所有可置换的物理页面。
CPU利用率和并发进程数的关系:进程数少,CPU利用率低,增加并发进程,导致内存访问增加,降低CPU利用率。当并发进程增加到一定数量,再增加会导致CPU利用率迅速降低。
-
工作集算法
-
工作集:假设当前时刻为t,时间窗口大小为α,一个进程在[ t-α,t]的时间段内,使用的逻辑页的集合。工作集随着时间不断变化。进程的不同阶段,对内存的需求都不同。当内存访问的局部区域位置稳定时,工作集稳定,当局部区域位置改变时,工作集快速扩张或收缩,过渡到下一个稳定值。
-
常驻集:当前时刻进程实际驻留在内存中的页集合
工作集是进程在运行过程中的固有性质。常驻集取决于系统分配给进程的物理页数量和页面置换算法。
通过控制常驻集的大小,影响缺页率:若工作集是常驻集的子集,则缺页少;若工作集发生剧烈变动,则缺页多;进程常驻集大小到达一定数量,缺页率不会明显下降。
- 工作集算法思路:设置内存访问链表,维护时间窗口α内的访问页面链表。访问内存时,换掉常驻集中,不在工作集中的页面。缺页时,换入页面。注意:区别于局部置换算法,该置换算法并不一定在缺页时才进行置换。
-
-
缺页置换算法
-
缺页率=缺页次数/内存访问次数,或缺页平均时间间隔的倒数。影响缺页率的因素:置换算法、物理页面数、页大小、编程方法等。
-
进程的物理页数越多,缺页率越低。
-
缺页置换算法思路:
通过调整常驻集的大小,使每个进程的缺页率保持在一定范围内。若缺页率高于上限,增加常驻集以分配更多的物理页面数。若缺页率低于下限,CPU效率低,减少常驻集以减少物理页面数
访存时,设置引用位标志(是否访问)。缺页时,计算从上次缺页时间间隔T = |t_last - t_now|。若 T > α(窗口大小),缺页率低,置换所有t_last到t_now时间间隔内没有被访问的页。若T <= α,缺页率高,增加缺失页到常驻集中。
-
-
2.5 抖动
抖动:驻留内存的进程过多,导致进程物理页过少,不能包含工作集,造成大量缺页,频繁置换,运行速度慢。操作系统需要在并发和缺页率之间达到平衡。