操作系统 内存资源管理
那我们就从内存访问开始8
为什么要进行内存管理?
- 在原来的批操作当中,我们系统只会运行一个程序,在前一个程序结束后从主存当中进行切换。这种不断在主存当中切换会产生很高的消耗。如何让多个程序同时在内存当中以提高进程切换时的响应速度。
- 多个任务需要内存空间
- 不管硬件设备多好,需求总会大于实际内存
- 进程总是希望能够占有内存空间(我们通过虚拟内存的方式,让进程假装以为自己拥有内存)
内存物理组织
电脑的主存至少有两层记忆原件组成 内存和主存
重定位技术
为了良好的封装效果,程序员不能决定程序在内存当中执行的位置。这可以有效的控制利用空闲的空间。内存当中即插即用的做法
重定位的结果:
- 在交换到主存前后,进程在内存当中位置会改变
- 物理地址和内存引用对程序员透明
- 内存压缩也会使得进程在内存中位置改变
地址管理
- 物理地址 无论重定位技术如何使用,我们只要执行都必须和硬件接轨。是使用的绝对地址
- 相对地址 逻辑地址的一种特殊情况,以某点为基址地址(相加)的地址构建
相对地址的优点:
- 更好的完成数据共享
- 代码可以根据模块进行组织(编译 链接 调试)和段相关
- 对于内存提供只读 可写 不同层级的保护
- 每个相对地址都会被映射到主存上
共享的优点:
- 相对地址指向同一个区域 即可完成共享内存(但是两个程序可能并不知道彼此的存在)
- 站在用户的角度来说 可以让不同的用户共享到相同的内容(而不是通复制的方法,那会大量的增加负担)
内存保护
- 由于使用相对地址管理,很容易出现内存访问越界的情况,我们采用一个limit register进行控制
- 由于重定位的原因,进程的物理地址可能会切换
- 因此更多的内存保护技术是由硬件而不是操作系统来完成的(硬中断)
内存管理算法
解决方法1:内存抽象 (构建逻辑地址)
优点:不需要进程得知物理地址安排的多少
抽象方法:base register limit register 检查方式(logical address + base > limit == error)
解决方法2:swap策略(占用内存要占用哪块?)
一、固定分区
产生内零头 对主存利用不够充分,必须设计overlay的方式来解决大程序的载入问题
- 平均分区
优:简单,不需要设计算法
随意分配,但是内存很多
缺:不能运行大程序 (overlay基本不可能实现) 进程的数量受到分区数限制 内存的利用率很低
- 不等长分组
- 对于分组形成队列 根据算法确定分区 来尽量减小内零头
二、动态分区
分组采用动态分组的方式,要到正好自己需要的内存区间
缺点:
产生外零头
- 解决方法:紧凑型(但是会导致效率很低)
- 解决方法:伙伴系统 抽到最近的2^n的内容,如果内存释放,和自己等大的伙伴进行合并
由于固定分区的非非平均分组带来的问题就是放置算法
- 最佳匹配: 选择与要求大小最接近的块
- 首次匹配:从头开始扫描内存,找到最近的可以放置的一块
- 下次匹配:从上一次放置的位置开始扫描内存
- 最差匹配:和最佳匹配相反,总是选择最大的分区
- 快速匹配:把不同大小的内容放在不同的分区当中,每次快速找到,类似哈希表那种快速搜寻的方式
单个分区的角度来看,最佳匹配是最优的,但是如果有多个分区的话,大分区没有被占用则可以让不是最佳匹配的进程使用
虚拟内存的管控 分页和分段
分页:内存被划分为大小固定相等的块 ,且块相对比较小,进程中成为页的块可以指定到内存中称为页框。
浪费的内存空间仅是最后一个分页的部分内容。
一个页表的结果包括
每个page都对应这几个标识位:
- 标识位表示是否被引用
- protection表示对于当前页框的内存保护,不能被其他的进程访问 并且不同段给予不同的权限(比如代码可执行)
- present表示当前页标是否缺席
页表
每一个进程维护一个页表,使用逻辑地址来解决这种问题
逻辑地址包括页号和对应的偏移量 转化成为偏移量
页号访问页表生成逻辑地址的前半部分
页的大小和页框的数量都是2的幂,会方便进行逻辑寻址
一页大小的选择
更小的页大小会导致需要更大的页表
二级记忆同样需要更大的页标
分段
分段:把程序和其相关的数据划分到几个段中 段虽然有最大限度,但是不要求所有的段大小先等
分段的分区同样也可以不是连续的。
分页的优点在于对程序员可见,更符合进程使用的需求,进程需要访问资源通常都是大小不一的,一个小的整体,往往会被分页放在不同的位置上
缺点:程序员必须知道段表的最大长度限制
段表
每一个段表包括
- 该段长度 和页表不同的地方
- 是否载入内存
- 是否被修改
段表和页表的优点
段表和页表都都相当与对于内存进行抽象,可以通过表完成共享、保护、检查等功能
需要避免的缺点:
如果表当中内容载入一半,发生了错误,就需要全面销毁,这会浪费很多的时间
解决方法:尽量把容易发生错误的段载入放在头部
结合两种的优点为段页式:
虚拟地址组成为(其实和二级段表、页表类似)
- 段号
- 页号
- 偏移量
利用分页的消除外部碎片和分段的可变动大小和可见
虚拟内存当中内存管理的实现
虚拟内存的定义:
备用内存虽然是主存的一部分。虚拟存储的大小受到计算机系统寻址机制、可用备用内存量的限制
缓存的使用:page先去缓存找,如果不对,再去page table当中寻找
优点
- 在内存当中保留多个进程 任何时刻都会有进程装入它的某些块当中
- 进程可以比内存的全部空间还大
虚拟页表:
除了虚拟内存的优点,容量的增大同样会带来页表的增大。
- 多层页表来解决 导致页标出现了多个入口,相当于增加结构层次
- 构造一个索引链 双向索引自己找自己 (链指针)
内存交换技术
我们为了保证每个程序都处于就绪状态,部分程序的内容不载入到内存当中
在调用当中存在局部性规律:
- 程序和数据在进程载入当中呈聚集的态势
- 在一段时间内,一般只需要运行几个进程
为什么出现这种情况:
- 代码顺序执行
- 代码存在循环语句(要到的都是一致的资源)
- 局部变量基本都在栈顶的
内存多了的处理方法
- 重新写回磁盘
- 如果没有更改(有备份)可以直接载入到程序当中
内存交换条件:page fault 需要的条件不在主存中
置换算法
- 最优算法 看到未来(就尼玛离谱),最后做访问的替换
- 先进先出 把最先载入的踢出去
- 最远输出 把最先被访问的(有的内存可能中间又被访问了一次即更新)
- 时钟算法,LRU虽然是比较优良的一种算法,但是在调度和算法实现上面临着很多问题,时钟算法能在页面数目比较多的情况下 和LRU达到近似相同的结果
时间算法叙述:
增加一位使用位:
- 第一次被载入设置为1
- 被引用,设置为1
- 当发生page fault的时候,遇到1变成0,然后跳过,遇到一个0则占用。如果都占用,就会使用第一位