目标
前言
基本概念(25min)
计算机系统:
- 没有应用程序,用户也可以和操作系统做简单交互
- OS是一种最基本的系统软件;控制和管理硬件和软件等计算机资源;为用户、软件提供简单的服务
OS的功能:
(计算机资源的管理)
- 文件管理
- 内存管理
- CPU调度
- 设备管理
(为用户和应用程序提供服务)
- 命令接口
- 联机命令:交互式的命令行(如CMD)
- 脱机命令:批处理(一堆预先写好的命令行,如.bat文件)
- 程序接口:操作系统预先提供的(由系统调用组成,程序接口=系统调用,操作系统预制好的一些“API”供你调用)
- GUI界面
OS的特征:
- 并发性(程序运行)
- 并发:宏观上是同时发生的,但微观上是交替发生的。多道程序技术与os的并发一起诞生。
- 并行:两个或多个事件在同一时刻发生
- 共享性(资源访问)
- 互斥共享:同一时间只允许同一进程访问该资源
- 同时共享:同一时间只允许多个进程“同时”访问该资源
- 虚拟化:把实际存在的物理上的实体抽象成多个逻辑上存在的对应物,而用户能够感受到的就是逻辑上的
- 利用辅存增加CPU的容量(空分复用技术)
- 时间片轮转,看似同时处理多个进程(时分复用技术)
- 异步:一个进程不是一下子执行完的,而是走走停停。有了并发,才有了异步。
OS的分类
- 单道批处理系统:内存中只有一个作业(解决了IO和CPU速度不匹配的矛盾,存在资源利用率低的缺点)
- 多道批处理系统:内存中有多个作业,通过作业调度交替运行(解决了资源利用率低的缺点,存在交互性不高的缺点)
- 分时操作系统:时间片轮转地为多个用户服务,提高了交互能力(解决了交互性的问题)
OS的运行机制:
- 指令:CPU识别和执行的最基本命令
- 特权指令:核心态(管态)下运行
- 非特权指令:用户态(目态)、核心态下运行
- 两种CPU状态:
- 核心态:可运行特权、非特
- 用户态:可运行非特
- 两种程序:
- 内核程序:运行特权指令,实现了OS的内核功能
- 应用程序:运行非特权指令
OS的内核:
- 大内核:时钟管理、中断、原语+文件管理、内存管理、CPU管理、设备管理…
- 缺点:代码混乱,难以维护
- 优点:执行的效率高
- 微内核:只实现时钟管理、中断、原语这些核心功能
- 缺点:频繁地在用户态和核心态进行切换,性能低
- 优点:结构清晰,方便维护
中断:
- 中断发生时,CPU暂停运行,CPU进入核心态,由操作系统对中断进行处理
- 中断的分类:
- 内中断:信号来自当前正在CPU中执行的指令
- 自愿中断:
- 强迫中断: 硬件问题:缺页?内存不够? 软件问题:整数除0?
- 外中断:来自外部设备
- 内中断:信号来自当前正在CPU中执行的指令
- 外中断的处理过程:
- 执行完一个指令,CPU要检查是否有外中断
- 检测到中断,则保存被中断进程的CPU环境(如程序状态字、程序计数器、通用寄存器等)
- CPU转为核心态,根据中断信号类型,转入响应的中断处理程序
- 退出核心态,恢复保存的CPU环境,继续执行进程
系统调用:操作系统定义的一些函数,供用户程序调用。核心功能需要特权指令来完成,因此只能运行在核心态
- 功能:也就是OS中,提供用户的简单服务的那四个功能+进程通信
- 系统调用与库函数的区别:有的库函数是简单的函数,有的则需要调用到系统调用函数(创建文件…)
CPU调度(17min)
调度的分类:
- 高级调度(作业):从外存队列的作业中选择进行新建进程,到达内存,进入就绪队列
中级调度(内存):内存中的进程被暂时调到外存,进入挂起队列;再从挂起队列中调回内存- 低级调度(进程):进程执行
进程调度的分类
- 非剥夺式
- 剥夺式:如果一个进程正在CPU上执行,此时有一个优先级更高的进程进入就绪队列,则被抢占
调度算法的指标:
- CPU利用率 = CPU忙碌时间 / 总时间
- 系统吞吐量 = 总共完成了多少道作业 / 总时间
- 周转时间
- 作业周转时间 = 作业完成时间 - 作业到达时间
- 平均周转时间 = 周转时间之和 / 作业数
- 带权周转时间 = 作业周转时间 / 作业实际运行时间
- 平均带权周转时间 = 带权周转时间之和 / 作业数
- 等待时间
- 等待时间 = 周转时间-运行时间-IO服务时间(如果有的话)
- 平均等待时间 = 等待时间之和 / 作业数
- 响应时间:用户提交请求到首次响应的时间
- 相应比:(等待时间+运行时间) / 运行时间
调度算法:
-
先来先服务(FCFS):
- 优点:算法简单、公平
- 缺点:对长作业比较有利,对短作业不利
- 不会导致饥饿
-
短作业优先(非抢占式)(Shortest Job First):
-
抢占式短作业优先
- 优点:最短的平均等待时间和周转时间
- 缺点:
- 对短作业有利,对长作业不利
- 会导致饥饿
-
时间片轮转调度算法(分时)
- 时间片太大:退化成先来先服务,响应时间长
- 时间片太小:进程切换过于频繁
- 不会导致饥饿
-
优先级调度算法(抢占、非抢占)
- 静态优先级
- 动态优先级:如:高响应比调度算法 :每一次调度都计算响应比=已经等待时间+运行时间 / 运行时间,然后选取相应比最大的那一个
-
多级反馈队列:
- 有k个时间片从小到大、优先级从高到低的反馈队列
- 新进程到达时,先进入第一个队列,按照先来先服务依次运行,运行完一个时间片之后若还没有完成,则被放入下一个队列的队尾,如果当前就是最后一个队列,则放入当前队列的队尾
- 抢占式的调度。新进程到达时,正在运行的更下层队列中的进程会被抢占。
- 会导致饥饿
进程(15min)
进程上下文:进程执行全过程的静态描述
- 上文:已经执行过的寄存器、堆栈中的指令、数据
- 正文:正在执行的寄存器、堆栈中的指令、数据
- 下文:将要执行的寄存器、堆栈中的指令、数据
进程的定义:
- 进程是程序(进程实体)的一次执行
- 系统进行资源分配、调度的最基本单位
进程的组成:
- 程序段
- 数据段
- PCB:操作系统对其进行管理需要的各种信息(pid\uid…),是进程存在的唯一标志
进程的组织(多个进程):
-
链接方式:按照进程的状态(执行、等待…)创建多个队列,OS持有指向各个队列的指针
-
索引方式:队列替换成指针(队列中的每一个进程有各自的索引指针)
进程的特征
- 并发性:
- 异步性:
- 结构性:由数据段、程序段、PCB组成
- 独立性:独立接受资源分配、独立接受调度的最基本单位
- 动态性:是程序(进程实体)的一次动态执行
进程的状态与转换:
- 三种状态:
- 运行态:正在CPU中运行的进程
- 就绪态:已经具备运行资源,正在等待CPU
- 阻塞态:等待某种资源
- 创建态
- 终止态
- 状态的转换:
进程控制: - 创建原语:创建空白PCB,为其分配资源,放入就绪队列
- 终止原语:运行->终止
- 阻塞原语:运行->阻塞
- 唤醒原语:阻塞->就绪
- 切换原语:运行->就绪;就绪->运行
进程通信:无法直接访问对方
- 共享存储:两个进程共享资源,是一种互斥共享
- 管道通信:开辟一个缓冲区。一个进程写,另一个进程读
- 消息传递:
- 直接通信方式:每一个进程维护自己的消息队列
- 间接通信方式:信箱作为中转
线程(10min)
进程和进程可以并发,进程内部能否并发?引入线程之后,1. 进程内部(线程)的并发度 2. 线程管理(用户态-》核心态的时间) 是两个需要权衡的因素
线程:理解为轻量的进程,处理机调度的最小单位(资源分配的最小单元依然是进程),增加了进程内部的并发度
- 线程的分类:
-
只支持用户级线程的系统(多对一映射):【用户层面】多个用户级线程;【内核层面】一个内核级线程(进程)。
- 优点:线程管理是由用户空间的线程库来完成的,系统调用少,系统开销小
- 缺点:并行性差:1. 多个线程无法并行运行 2. 一个线程阻塞,整个进程阻塞
-
支持内核级线程的系统:【用户层面】多个用户级线程;【内核层面】多个内核级线程。
-
一对一的映射:
- 优点:并发度高:1. 多个线程能够并发执行 2. 一个线程阻塞不影响其它线程
- 缺点:一个用户线程需要创建对应的一个内核线程,系统开销大
-
多对多的映射:
- 优点:兼顾
-
-
进程的互斥和同步(30min)
临界资源:一种互斥共享资源,一个时间只能被一个进程访问
- 访问临界资源的过程如下:
- 进入区:进程检查是否能够访问这个临界资源,若能访问,则上锁
- 临界区:实际访问临界资源的代码
- 退出区:用完,解锁
- 访问临界资源(进程互斥)的四个原则:
- 空则让进
- 忙则等待
- 有限等待:不发生饥饿
- 让权等待: 一旦不能在临界区时,马上释放CPU
进程同步和互斥:
- 同步:进程的执行有先后关系
- 互斥:进程互斥地访问同一个临界资源
互斥的软件实现:
-
单标志法:
- 大致思路:设置一个标志,0表示目前0号进程能访问临界资源,1表示…。对于0号进程,一开始通过while(flag!=0)来决定是否是等待、还是占用。
- 缺点:flag的初始值决定了进程的访问顺序,若flag初始化为0,必须要等到0进程访问完,其它进程才有可能访问,违背了**”空则让进“**的原则,
-
双标志先检查法:增加一个标志位
- 大致思路: 增设一个标志位,解决单标志法中空则让进不满足的问题
- 缺点:进入区中的1. 判断另一进程是否占用资源 2. 给当前进程上锁 不是一个原语,会导致两个进程同时占用一个临界资源,违背了**”忙则等待“**的原则。
-
双标志后检查法:将1. 判断 2. 上锁的顺序颠倒
- 缺点:其实和上一种方法一样,两个进程一起上锁,就违背了**”空则让进“、”有限等待“**的原则。
- 缺点:其实和上一种方法一样,两个进程一起上锁,就违背了**”空则让进“、”有限等待“**的原则。
-
Peterson算法:再增加一个标志,表示可以优先让给哪一个进程
- 大致思想:举一个现实生活中的例子:我想用吹风机(上锁),但如果你想用,我会优先给你用(谦让),但如果此时你虽然也想用吹风机(上锁),但你也表示如果我想用的话会优先给我用(谦让)。虽然此时双方都陷入循环,但在我的下一次循环判断时,发现了对方的谦让,于是我可以退出循环,先用这个吹风机。
- 缺点:由于while的存在,会违背让权等待的原则。
- 大致思想:举一个现实生活中的例子:我想用吹风机(上锁),但如果你想用,我会优先给你用(谦让),但如果此时你虽然也想用吹风机(上锁),但你也表示如果我想用的话会优先给我用(谦让)。虽然此时双方都陷入循环,但在我的下一次循环判断时,发现了对方的谦让,于是我可以退出循环,先用这个吹风机。
信号量:使用原语来对信号量进行操作,实现进程的同步和互斥
-
原语 :wait(P)(查看资源(检查)+修改信号量(上锁)是一个函数)和signal(V)(释放资源),彻底解决单标志、双标志、peterson的不足。
-
整型信号量:用一个整数型的变量来表示某种资源的数量。wait(资源);临界区;signal(资源)。缺点:无法进入临界区的进程会一直执行wait中的while,违背了让权等待。
-
记录型信号量:增加一个等待队列。如果一个进程暂时无法占用资源,该进程就被加入到该资源所对应的信号量的等待队列中,从而避免了while循环,满足了让权等待原则。
-
使用信号量来实现进程互斥、进程同步:
- 互斥:信号量初值为1
- 同步:信号量初值为0,先运行的代码之后进行V操作;后运行的代码之前进行P操作
进程的生产者消费者问题:两个进程。1. 对缓冲区有互斥关系,空满两对同步关系 2. 当缓冲区为空->full=0,生产者先执行,所以V(full)写在生产者的临界区之后;P(full)。。。 3. 当缓冲区为满->empty=0,消费者先执行,所以V(empty)写在消费者的临界区之后;P(empty)。。。 4. 互斥写在同步的里面,考虑:此时empty=0,一定是消费者要先执行,而如果此时生产者执行,互斥信号量为0,则发生死锁。5. 临界区代码尽可能少:
进程的多生产者多消费者问题(父亲母亲、女儿儿子,女儿吃父亲放的苹果,儿子吃母亲放的橘子):
- 互斥:盘子:mutex=1
- 同步:
- 当放入苹果后,女儿才能取苹果:apple=0
- 当放入橘子后,儿子才能取橘子:orange=0
- 女儿、儿子取完之后(盘子空),父亲、母亲才能放水果:plate=1
读者写者问题(两个写进程,两个读进程 ):
- 读者和写者互斥、写者和写者互斥:rw=1的互斥信号量
- 读者和读者不需要互斥:count=0的互斥信号量
- count的临界访问:mutex=1的互斥信号量
- 写者的优先问题:w=1的互斥信号量
哲学家进餐问题:
- 设置一个初始值为4的信号量,保证同一时刻最多有四个哲学家竞争
- 吃饭前,保证能够同时拿到两个筷子
- 奇数位的哲学家优先拿左侧,偶数位的哲学家优先拿右侧
管程(10min)
信号量需要进程自己实现,管理起来麻烦,也容易出现错误,导致死锁。管程将进程中的临界区集中起来管理,定义了一个数据结构将互斥、同步操作封装起来,而对进程不可见。
为临界资源定义一个数据结构,并向外提供对其操作的函数。对于互斥,管程定义了入口队列,确保同一之间只有同一进程在管程中;而对于同步,管程定义条件变量(如x、y等),当一个进程执行x.wait()时,该进程被挂起,直到有一个进程执行了x.signal,而当一个进程执行x.signal时,有三种情况 1. x变量上没有挂起进程,则该操作无效 2. 有,挂起进程等待当前进程执行完,才开始执行 3. 有,当前进程等待挂起进程执行。
死锁(20min)
在并发环境下,各个进程互相等待对方手中的资源,导致各个进程都阻塞,无法向前推进
三个不同的概念:
- 死锁:进程互相等待对方手中的资源,发生死锁一定有两个以上的进程,一定处于阻塞态
- 饥饿:发生饥饿的进程可能只有一个,可能处于就绪态(得不到调度运行);也可能处于阻塞态(得不到资源)
- 死循环:进程处于运行态(是你自己代码写得烂!!!而其它的是操作系统的问题)
死锁的必要条件:
- 互斥:互斥共享的临界资源
- 不可剥夺:进程还没使用完资源,则不会被强行抢占
- 请求并保持:占有一定资源的进程,请求占有其它已被占有的资源而受阻后,依然保持自己的资源
- 循环等待链
死锁的应对策略
- 死锁的预防
- 破坏互斥条件:
- 思想:使用SPOOLing技术把互斥共享资源改成逻辑上同步共享的资源
- 缺点:系统安全性差
- 破坏不可剥夺条件:
- 思想:操作系统能够帮助进程强行剥夺
- 缺点:实现麻烦;容易破坏之前正在运行的进程的环境;换来换去系统开销大
- 破坏请求并保持条件:
- 思想:静态资源分配法:进程运行之前,必须要申请到所有资源
- 缺点:资源的利用率很低
- 破坏循环等待条件:
- 思想:顺序资源分配法: 为资源编号,每一个进程只能按照编号从小到大申请资源,一定不存在循环等待链
- 缺点:编号顺序不代表资源的需求顺序,资源的利用率很低
- 破坏互斥条件:
- 死锁的避免:
- 安全序列:按照安全序列给进程分配资源,进程都可以完成,如果有安全序列,系统处以安全状态。处于不安全状态,不一定发生死锁(触发死锁的借款还没来临),如果发生死锁,一定处于不安全状态。
- 银行家算法:
- 死锁的检测和解除
-
资源分配图:
- 请求边:进程指向资源
- 分配边:资源指向进程
-
检测:
-
解除:
- 资源剥夺法:暂时挂起某些死锁进程
- 撤销进程法:强制撤销某些死锁进程
- 进程回退法:让一个进程回退到可以避免死锁的地步
-
内存(1hour)
编址&地址长度:
- 按字节编址:存储单元大小无脑=1字节
- 按字编址:需要看计算机的字长
- 地址长度:总内存大小 / 存储单元大小,得到存储单元个数,进一步得到地址长度
编译的过程:
-
编译原理:【源程序】–预处理器–>【预处理过后的源程序】–编译器–>【目标汇编程序】–汇编器–>【可重定位的机器代码】–链接器–>【可执行的目标程序】
-
王道:
-
装入模块装入内存的三种方式:
- 绝对装入:编译过程中就知道要存入内存的位置,装入模块中的地址直接为绝对(物理)地址。
- 特点:适用于单道处理系统。
- 静态重定位:在装入过程中对地址进行重定位(逻辑地址->物理地址)。
- 缺点1:需要一次性全部装入
- 缺点2:装入之后就不能移动
- 动态重定位:在运行过程中,通过重定位寄存器,对地址进行重定位
- 优点1:可以部分装入、不连续装入
- 优点2:装入之后可以移动(只需要修改重定位寄存器的值)
- 绝对装入:编译过程中就知道要存入内存的位置,装入模块中的地址直接为绝对(物理)地址。
-
链接的三种方式:
- 静态链接:装入前链接成一个完整的装入模块
- 装入时动态链接:装入过程中链接
- 运行时动态链接:运行过程中链接
内存中内部碎片和外部碎片:
- 内部碎片:分配给进程的内存区域没有被完全用上
- 外部碎片:某些空闲分区因为太小而无法分配—>紧凑技术
内存的管理:
-
内存的分配与回收:
- 连续分配:
- 单一连续分配(单道):内存只分为系统区+用户区,用户区被一个用户进程独占
- 优点:实现简单、没有外部碎片
- 缺点:内部碎片:分配给进程的内存区域中,有部分没有被用上
- 固定分区分配:
- 分区大小相等:
- 分区大小不等:
- 数据结构——分区说明表:
- 优点:不会产生外部碎片(所有分区都装不下接下来的进程,此时进程仍然可以通过覆盖的技术装下)
- 缺点:会产生内部碎片
- 动态分区分配:
-
数据结构——空闲分区表\空闲分区链
-
【如何分配?】
- 首次适应算法:空闲分区按照地址递增排序(具有最佳适应算法的优点)
- 最佳适应算法:空闲分区按照容量递增排序
- 最坏适应算法:空闲分区按照容量递减排序
- 邻近适应算法:空闲分区按照地址递增排序,每一次从上一次查找结束的位置开始查找(具有最坏适应算法的缺点)
-
【如何回收?】–>如果有连续的空闲分区,则合并;如果有新的空闲分区,则添加
-
优点:没有内部碎片
-
缺点:有外部碎片(通过紧凑的技术来处理–>采用动态重定位的装入方式,每一次移动一个进程,修改它的PCB,在运行过程中访问PCB,取出开始地址存入重定位寄存器,开始重定位)
-
- 单一连续分配(单道):内存只分为系统区+用户区,用户区被一个用户进程独占
- 非连续分配:
- 基本分页存储(由固定分区分配改造):
- 概念:内存被分为一个个页框(页帧、内存块、物理块);相应的,进程被分为一个个页(页面)
- 地址的转换:
- 逻辑地址 / 页面大小 = 页号;逻辑地址 % 页面大小 = 页内偏移量
- 逻辑地址 / 页面大小 = 页号;逻辑地址 % 页面大小 = 页内偏移量
- 页号所对应的内存起始位置 (一个进程对应一个页表):
因为进程的页表也连续存储于内存,所以页号可以被隐藏。假设页表项大小Y,进程的某个逻辑地址的页号为M,只需知道页表在内存的起始位置X(X、页表长度(表示页表项的个数)、页表项大小Y,都存储在了页表寄存器),就可知道页表项存于X+MxY - 实例:
- 进一步改进——页表项大小的扩充:页表也存在内存中,一个页框里可能有内部碎片,因此有时需要扩充页表项的大小(2)。页号不变,实际的页表项位置=起始位置+页号x页表项大小2
- 进进一步改进——快表:
- 流程:
- 命中率的计算:
- 流程:
- 进进进一步改进——两级页表
- 单级页表的问题: 页表太大、又需要连续存储、进程只访问局部的页表项
- 注意点:采用多级页表,每一个页表都不能大于页面大小
- 流程:
把原页表分成<页面大小的一个个块(二级页表),建立一级页号目录表
- 基本分段存储:
-
实例:
-
段页不同:
- 分页对用户不可见;分段存储的段名由用户自定义、对用户可见, 可读性更高
-
分页的进程地址一维;分段二维
-
分段存储更容易实现信息的共享和保护
-
单级分页:2次访存;单级分段:2次访存
-
分页产生内部碎片;分段产生外部碎片
-
- 段页式存储:先分段再分页
- 实例:
- 实例:
- 基本分页存储(由固定分区分配改造):
- 连续分配:
-
内存空间的扩充:
- 覆盖:不用了
- 交换:把就绪态或者是等待态的进程暂时换到外存,PCB常驻内存,存储了外存的位置
- 换到外存的哪儿?:外存分为对换区和文件区,对换区的IO速度更快
- 什么时候换?:内存比较紧张
- 换出策略?:
- 虚拟内存:
- 传统存储管理方式的缺点:
- 一次性:只能一次性全部装入
- 驻留性:只有运行外,进程才会被移出内存
- 时间局部性:指令、数据被访问、执行,很有可能会被再次访问。
- 空间局部性: 存储单元被访问,它周围的存储单元很有可能会被再次访问。
- 虚拟内存的最大容量&实际容量:
- 虚拟内存技术的实现:
- 基本-》请求分页存储管理:
- 新增的四个字段:
- 状态位:当前页面是否在内存中
- 访问字段:访问了多少次,用于置换时判断
- 修改位:记录是否被修改,换出时是否需要覆盖外存
- 外存地址
- 实例:
- 页面的分配&置换算法(尚未考虑内存满不满):
-
驻留集:请求分页存储管理中,给进程分配的物理块的集合
-
固定分配:集合固定
-
可变分配:集合可变
-
局部置换:缺页时只能选自己的物理块
-
全局置换:缺页时可以选其它进程的物理块
-
固定分配局部置换:
-
可变分配全局置换:
-
可变分配局部置换:
-
- 页面的置换算法(缺页中断时,如果内存满):
-
最佳置换:
- 原理:发生缺页中断时,查看未来的访问序列,哪一个页面最久之后才会被访问
- 实例:
- 缺点:难以实现
-
先进先出置换:
- 原理:换出最先被调入内存的页面
- 实例:
- 缺点:belady异常:为进程分类的物理块数增加,缺页率不降反升。因为FIFO没能考虑程序执行的特征。
-
最近最久没有使用算法(LRU):
- 原理:换出最久没有被使用的页面
- 实例:
- 实例:开销大
-
时钟置换算法:
- 原理:最多循环两轮:
- 第一轮:调出访问位是0的,如果访问位是1,则改为0。如果都是1,则开始第二轮
- 第二轮: 调出访问位是0的,调入页面,访问位设为1,指针指向下一个页面
- 原理:最多循环两轮:
-
改进的时钟置换算法:同样没有被访问的,如果没有被修改,那就更好了
- 原理:最多循环四轮:
- 第一轮:检查(0,0) (没访问、没修改)
- 第二轮:(0,1),修改访问位(没访问、修改过)
- 第三轮:(0,0)(访问过、没修改)
- 第四轮:(0,1)(访问过、修改过)
- 原理:最多循环四轮:
-
- 页面的调入:
- 何时调入:
- 预调页策略:根据局部性原理,调入不久之后可能使用到的页面。进程运行前
- 请求调页策略:缺页才调入,进程运行期间
- 从何处调入:(一种)对换区不太充足时,不会被修改的数据从文件区直接调入内存;会被修改的数据在对换区和内存之间往返
- 何时调入:
- 页面置换中的抖动(颠簸)现象:
- 概念:刚被换出的页面马上又被访问
- 解决策略:适当增加进程的驻留集
- 工作集:在一段时间内,进程实际访问的页面集合
- 具体做法:保证驻留集略大于工作集
- 新增的四个字段:
- 基本-》请求分页存储管理:
- 传统存储管理方式的缺点:
-
逻辑地址和物理地址的转换:
- 绝对装入:
- 静态重定位:
- 动态重定位:
-
内存保护:让进程只能访问它自己的空间
- 方法1:上限寄存器+下限寄存器:上限寄存器<=物理地址<=下限寄存器
- 方法2:重定位寄存器+界地址寄存器:逻辑地址<=界地址寄存器,如果满足,物理地址=逻辑地址+重定位寄存器