(PS:个人课下整理的操作系统笔记,OneNote直接拷贝过来的,图片看不了就将就一下,配合张伟老师的PPT看效果更好)
一、背景
1.内存(Main memory)是CPU唯一能直接访问的大容量存储机构
2.内存由很大一组字或者字节组成,每个字或者字节有他们自己的地址,CPU根据程序计数器的值在内存中取指令,这些指令可能引起更进一步的取址
3.每个进程在内存中的分配空间大小取决于:基址寄存器(Base register)和长度寄存器(Limit register)
4.地址的不同表现形式:
- 字符地址——可重定位/逻辑/虚地址——绝对地址
- 多道程序系统中,将用户源程序变为内存中可执行程序分为3步骤——编译、链接、载入
5.地址绑定(binding)——将指令和数据绑定到内存地址,可以发生在以下3个阶段:
- 编译时:编译时就知道进程在内存中的驻留地址,则可以生成绝对代码
- 加载时:如果编译时不知道进程的驻留地址,那就要生成可重定位代码
- 运行时:如果进程在运行时可以从一个内存到另一个内存,那么捆绑要延迟到运行时执行。(外部碎片の解决方法の紧缩要求在这一阶段完成)
6.逻辑地址与物理地址的区别
- 逻辑地址——CPU生成的地址
- 物理地址——内存单元能看到的地址
- 编译和加载时生成相同的逻辑地址和物理地址,运行时地址捆绑方案会导致逻辑地址和物理地址不同
7.内存管理单元(Memory-Management Unit,MMU)——运行时,从逻辑地址到物理地址的映射
- 在MMU方案中,用户进程的地址在送到内存之前,会加上重定位寄存器的值,用户程序看不到真正的物理地址,内存映射硬件将逻辑地址转变为物理地址
8.动态加载(Dynamic Loading)(由于进程的大小受内存大小的限制,为获得更好的空间利用率,可使用动态加载)
- 一个子程序(routine)只有在调用时才被加载到内存,所有子程序以可重定位的方式保存到磁盘上
- 优点:不使用的子程序绝不会装入内存,比如一大堆异常处理代码,特别适用
- 动态加载不需要操作系统提供特别的支持,由用户自己设计程序
9.动态链接(Dynamic Linking)——将链接延迟到运行时
- Stub存根——一小段代码,将不在内存的程序装入对应的链接库
- 当存根执行时,它首先检查所需子程序是否已在内存中。如果不在,就将子程序装入内存。不管如何,存根会用子程序地址来替换自己,并开始执行子程序。
- 动态链接也适用于库(libraries)更新(如改进版)。
10.交换(swapping)//常考——CPU可以暂时从内存中交换出来放在后备存储上,当需要时再换回内存中
- CPU调度算法用轮转法
- 常用于基于优先级的调度策略,高优先级的进程换入,低优先级的进程换出,有时也称为滚出滚进
- 交换出的进程需要再换入,编译和加载时绑定需要换回源地址,运行时绑定不需要
- 交换时间的主要部分是转移时间
二、内存管理机制之一——连续空间分配(Contiguous allocation)
1.框架搭建:
2.内存通常分为两个区域:
- 驻留操作系统的低地址区域(其实操作系统也可以在高地址,但是中断向量一般在低地址,所以通常也将操作系统放在低地址内存)
- 驻留用户进程的区域
3.内存保护:可重定位寄存器(有最小的物理地址值)和界限寄存器(有逻辑地址的范围)
4.可变分区分配(Variable-partition allocation)
- 孔(hole):连续的可以使用的内存块
- 从一组大小不同的可用孔中选择一个空闲孔的最为常用方法有:
- 首次适应:分配第一个足够大的孔。
- 最佳适应:分配最小的足够孔。
- 最差适应:分配最大的孔。
- 碎片(Fragmentation)
- 外部(external)碎片:连续分配的问题
- 解决方案:紧缩(compaction),把外部碎片都压到最后
- 满足紧缩条件必须要求是动态可重定位,且在运行时完成,为什么?(简答题)
- 因为运行时(可重定位地址+基地址)——进程需要从一个内存段转移到另一个内存段的情况,地址绑定则要延迟到运行时执行。
- 内部(internal)碎片:固定大小单元块分配的问题
- 外部(external)碎片:连续分配的问题
二、内存管理机制之二——非连续空间分配(Non-Contiguous allocation)
1.框架回顾:
2.分页(Paging),该方案允许进程物理地址空间非连续
- 帧——物理内存中固定大小的块
- 页——逻辑内存中固定大小的块
共2^m个bit,每一页装2^n个bit,一共需要2^(m-n)个页
- 例:
P是页表左边的数(0123),通过P找到对应右边页表中的数(1437),即物理地址中的帧,帧+偏移量d就找到了绝对地址
- 采用分页技术不会产生外部碎片,但会产生内部碎片
- Page size is 2048 B, process size 72776B, What’s the number of internal fragmentation?
需要35个页,和1096B, 共需要36个帧,2048-1096=952 B 内部碎片。
- 当系统需要执行一个进程时,它将检查该进程所需要的页数。因此,如果进程需要n页,那么内存中至少应有n个帧。
3.页表的实现
- 寄存器(在页表比较小的时候)
- 当页表非常大时,将页表放在内存中,并用页表基寄存器(Page table base register,PTBR)指向页表,每次改变页表只需改变该寄存器即可,但是每次需要访问内存两次,造成无法忍受的延迟;
页表长度(length)寄存器(PTLR)来表示页表的大小,该寄存器的值可用于检查每个逻辑地址以验证其是否位于进程的有效范围内。如果检查无法通过,会被操作系统捕捉到。
- 转换表缓冲器(Table lookaside buffer,TLB),小而贵,专用快速的硬件缓冲,TLB只包括页表的一小部分,能显著提高访问查找速度
TLB其实就是一个小页表,跟买彩票差不多,没命中还是去查页表
记住页表是一维数组,TLB是二维的
例:如果有80%的TLB命中率,需要20ns去访问TLB,100ns去访问内存,
则平均访问时间=0.8*120+0.2*(20+100访问内存中的页表+100访问内存)
4.分页环境下的内存保护
在分页环境下,内存保护是通过与每个帧相关联的保护位来实现的。通常这些位保存在页表中,任何一位都能定义一个页是可读、可写或只可读。有效无效位与页表中的每一条目相关联:(用在虚拟内存中)
- 当该位有效时,该值表示相关的页在进程的逻辑地址空间内,因此是合法的页。
- 该位无效时,该值表示相关的页不在进程的逻辑地址空间内。
5.页表结构(多层、哈希、反向页表)
6.分段(Segmentation)——分段是支持用户观点的内存管理方案。
Base和limit是段表本身内部的属性
STBR和STLR是描述段表的属性
记住段表是二维数组
例如我要引用段s号的字长d,我先比较d是否在limit长度范围内,如果符合再用base+d
- 分段的优点:
- 将段与对其的保护相关联
- 代码数据的共享
章末例题: