操作系统(二)
3 存储管理
逻辑地址与物理地址
-
逻辑地址,用户编程使用的地址空间
-
物理地址,程序执行使用的地址空间
-
地址转换:将逻辑地址转换为物理地址
主存复用
-
多道程序设计需要复用主存
-
按照分区复用:
- 主存划分为多个固定/可变尺寸的分区
- 一个程序/程序段占用一个分区
-
按照页架复用:
- 主存划分成多个固定大小的页架
- 一个程序/程序段占用多个页架
-
段式程序设计:把一个程序设计成多个段,代码段、数据段、堆栈段、等等
存储管理
-
段式存储管理:段式二维逻辑地址空间的程序占用多个主存可变分区
-
页式存储管理:一维逻辑地址空间的程序占用多个主存页架区
-
段页式存储管理:段式二维逻辑地址空间的程序占用多个主存页架区
存储保护
-
为避免主存中的多个进程相互干扰,必须对主存中的程序和数据进行保护
- 私有主存区中的信息:可读可写
- 公共区中的共享信息:根据授权
- 非本进程信息:不可读写
-
CPU检查是否允许访问,不允许则产生地址保护异常
虚拟存储
-
引入原因:
- 用户编写程序必须考虑主存容量限制
- 多道程序设计的道数受到限制
-
可行原因:
- 程序运行局部性原理:在一段较短的时间内,程序的执行仅限于某个部分,相应地,它所访问的存储空间也局限于某个区域。
-
实现思路:(核心)
- 局部性原理:一个程序只要部分装入内存就可以运行
- (磁盘)虚拟地址空间:容纳进程装入
- (主存)实际地址空间:承载进程执行
-
用户视角,计算机系统具有一个容量大得多的主存空间,即虚拟存储器
固定分区与可变分区
-
固定分区,既不适应大尺寸程序,又存在内存内零头,有浪费
-
可变分区:
- 按进程的内存需求来动态划分分区
- 创建一个进程时,根据进程所需主存量查看主存中是否有足够的空闲空间
- 若有,则按需要量分割一个分区
- 若无,则令该进程等待主存资源
- 由于分区大小按照进程实际需要量来确定,因此主存内的分区个数是随机变化的,会产生内存外零头,通过移动分区解决。
分页存储
- 分页实现:
-
主存划分为固定大小的页架
-
程序根据页架尺寸将逻辑地址分页
-
不同的页可以放在不同页架中,不需要连续
-
利用页表完成逻辑地址到物理地址转换
- 逻辑地址;页号+单元号,物理地址:页架号+单元号。从页号到页架号,查页表
-
基本思想:局部性原理,把进程全部页面装入虚拟存储器,执行时先把部分页面装入实际内存,然后,根据执行行为,动态调入不在主存的页,同时进行必要的页面调出
-
页的共享:不同进程通过页的共享来完成数据共享和程序共享
-
快表机制:
- 原因:页表放在主存,每次地址转换得访问两次主存。降低了存取速度。
- 第一次,访问页表,完成页号到页架号的转换
- 第二次,访问主存中的绝对地址(页架号+单元号)
- 解决:利用Cache存放部分经常访问的页表,快表内存放页号到页架号的映射
- 原因:页表放在主存,每次地址转换得访问两次主存。降低了存取速度。
-
缺页中断:
- 访问的页不在主存,由CPU发出缺页中断,需要操作系统将其调入主存后再进行访问。
- 主存若有空闲页架,则调入页
- 主存若无空闲页架,则通过页面调度算法淘汰页,如果调出的页有修改,则写回磁盘
- 更新快表和页表
- 访问的页不在主存,由CPU发出缺页中断,需要操作系统将其调入主存后再进行访问。
分段存储
-
基本思想:把进程的所有分段都存放在辅存中,进程运行时先把当前需要的一段或几段装入主存,在执行过程中访问到不在主存的段时再把它们动态装入。引入段表。
-
分段把主存分为多个段,段定义一组逻辑信息,代码段、数据段、堆栈段等等。更符合用户的需要。而分页是为了消减内存的外零头,通过离散分配和固定页架大小实现,提高内存利用率。页大小是固定的,段大小是可变的
段页式存储
- 段式存储管理可以基于页式存储管理实现。每一段不必占据连续的存储空间,可存放在不连续的主存页架中。
- 通过装入段中部分页面扩充为段页式存储管理。引入段页表。
页面调度算法
- 页面调度算法设计不当,会出现抖动:刚被淘汰的页面立即又要调入,并如此反复。
调度算法 | 原理 |
---|---|
OPT(最佳) | 当要调入新页面时,首先淘汰以后不再访问的页,然后选择距现在最长时间后再访问的页。只可模拟,不可实现。 |
FIFO(先入先出) | 总是淘汰最先调入主存的那一页,或者说主存驻留时间最长的那一页。只考虑到程序执行的顺序性,没考虑到循环性。 |
LRU(最近最少使用) | 淘汰最近一段时间较久未被访问的那一页。严格实现的代价大(需要维持特殊队列) |
LFU(最不常用) | 淘汰最近一段时间内访问次数较少的页面。每访问页1次就给这个页计数器加1,选择计数值最小的页面淘汰。 |
CLOCK(时钟调度) | 采用循环队列机制构造页面队列,形成了一个类似于钟表面的环形表。队列指针则相当于钟表面上的表针,指向可能要淘汰的页面。页面调入主存或被访问时,其引用标志位置1。淘汰页面时,从指针当前指向的页面开始扫描循环队列。把所遇到的引用标志位是1的页面的引用标志位清0,并跳过。把所遇到的引用标志位是0的页面淘汰,指针推进一步。每次逐出最近未使用的,是对LRU的一个低成本的模拟。LRU算法缓存淘汰算法虽然好,但是它的时间复杂度一定是o(n),因为需要遍历历史的数据。 |
MMU与反置页表
-
内存管理单元MMU:CPU管理虚拟/物理存储器的控制线路,把虚拟地址映射为物理地址,并提供存储保护,必要时确定淘汰页面
-
反置页表
- MMU用的数据结构,表项包含:正在访问该页框的进程标识、页号、标志位(有效、修改、锁定等信息)、哈希链指针。
- 反置页表是以页架号为索引,根据页架号来查页号,完成物理地址到逻辑地址的转换
-
反置页表引入原因:
- 一般页表存在的问题:大多数的操作系统会为每个进程提供一个页表。很占物理内存。
- 反置页表,所有进程共同使用一张页表,这张页表中的条目的数量和内存中物理的页框的数量是一样的,控制了页表的大小。使用反置页表虽然减少了内存的浪费,但是增加了查询时间并且增加了共享内存的难度。
-
基于反置页表的地址转换过程:
- MMU通过哈希表把进程标识和虚页号转换成一个哈希值,指向反置页表的一个表目
- MMU遍历哈希链找到所需进程的虚页号,该项的索引就是页架号,通过拼接位移便可生成物理地址
- 若遍历整个反置页表中未能找到匹配页表项,说明该页不在内存,产生缺页中断,请求操作系统调入
系统抖动
-
Belady现象:
- Belady现象是采用FIFO等算法时,可能出现分配的物理页面数增加,缺页次数反而升高的异常现象
- 原因:
- FIFO算法的置换特征与进程访问内存的动态特征矛盾,因为较早调入的页往往是经常被访问的页
- 被它置换出去的页面并不一定是进程近期不会访问的
4 设备管理
DMA(直接存储器访问方式)
- 替代处理器来控制主存和设备控制器之间的数据交换,否则是CPU轮询或中断设备控制器
- 流程:
- 处理器向DMA模块发出I/O命令
- 处理器继续执行其它工作,DMA模块负责传送全部数据
- 数据传送结束后,DMA中断处理器,由CPU执行中断服务程序来进行DMA结束处理。
- CPU不会终止原程序的执行,CPU只在数据传送的开始和结束时参与
- 开始时,CPU需要对DMA模块进行初始化
- 结束时,CPU响应中断,但不必保存现场
- DMA的周期窃取:
- 当DMA和CPU同时经总线访问内存时,CPU总是将总线的占有权让给DMA一个或几个主存周期
- 周期窃取对延迟CPU与主存的数据交换影响不大
- 数据传送过程是不连续的和不规则的
- CPU大部分情况下与Cache进行数据交换,直接访问内存较少
I/O缓冲:
- 解决CPU与设备之间速度不匹配的矛盾
- 单缓冲:输入输出共用一个主存缓冲区,然后和用户区的应用程序交互
- 双缓冲:输入缓冲区、输出缓冲区
- 循环缓冲:操作系统分配一组缓冲区,每个缓冲区度有指向下一个缓冲区的链接指针,构成循环缓冲。循环队列中有两种缓冲区,一种是没有数据的空闲缓冲区,一种是由数据的满缓冲区。又有两个指针分别指向空缓冲区和满缓冲区。
- 解决设备和进程速度不匹配的问题
- 为系统公共资源,供进程共享并由系统统一分配和管理
设备独立性:
- 作业执行前对设备提出申请时,指定某台具体的物理设备会让设备分配变得简单
- 应用程序与具体物理设备无关,系统增减或变更设备时不需要修改源程序。
- 设备独立性
- 用户通常不指定物理设备,而是指定逻辑设备,使得用户作业和物理设备分离开来,系统需要提供逻辑设备名和物理设备名的对应表以供转换使用。
SPOOLing技术:
- 思想:在输入和输出之间增加了“输入井”和“输出井”的排队转储环节。
- 预输入:操作系统将作业需要的输入数据成批从输入设备上预先输入至磁盘的输入缓冲区中暂存
- 调度作业执行时,作业使用数据不必再启动输入设备,从磁盘的输入缓冲区读入即可
- 缓输出:作业不启动输出设备,只是将输出数据暂存到磁盘的输出缓冲区
- 作业执行完毕后,由操作系统成批输出
- 好处:
- 提高了I/O速度
- 设备并没有分配给任何进程.在输入井或输出井中,分配给进程的是一存储区和建立一张I/O请求表。
- 实现了虚拟设备功能.多个进程同时使用一独享设备,而对每一进程而言,都认为自己独占这一设备,不过,该设备是逻辑上的设备。
5 文件系统
位视图
-
使用若干字节构成一张表,表中每一字位对应一个物理块,字位的次序与块的相对次序一致。字位为’1’表示相应块已占用,字位为’0’状态表示该块空闲。
-
其主要优点是,可以把位示图全部或大部分保存在主存中,再配合现代计算机都具有的位操作指令,故可实现高速物理块分配和去配,完成空闲块的管理
FCB 文件管理
Linux系统的FCB 中的文件名和其他管理信息分开,其他信息单独组成一个数据结构,称为索引节点 inode,此索引节点在磁盘上的位置由 inode 号标识。把 FCB 的主要内容与索引节点号分开,不仅能够加快目录检索速度,而且,便于实现文件共享。
Inode
-
文件系统中的每个文件都有一个磁盘 inode 与之对应,这些 inode 被集中存放于磁盘上的 inode 区。找到 inode,就能获得此文件的必要信息。
-
struct inode { unsigned long i_ino; /*inode号*/ atomic_t i_count; /*inode引用数*/ kdev_t i_dev; /*inode所在设备*/ … }
-
活动 inode 表:
- 磁盘 inode 记录文件的属性和相关信息,文件访问过程中会频繁地用到它,不断来回于内外存之间引用它,当然是极不经济的。为此,为此,在内存区开辟一张活动 inode 表。磁盘 inode 反映文件静态特性,活动 inode 反映文件动态特性。
- 当访问某文件时,若在活动 inode 表中找不到其 inode,就申请一个空闲活动 inode,把磁盘 inode 内容复制给它,随之就可用来控制文件读写。
- 当用户关闭文件时,活动 inode 的内容回写到对应的磁盘 inode 中,再释放活动 inode 以供它用。
-
多重索引:在UNIX系统中,每个i节点中分别含有10个直接地址的索引和一、二、三级间接索引。每个物理块512字节,每个块地址4个字节,每个块可以存放128个地址。
- 直接块容量=10×512B/1024=5KB
- 一次间接容量=128×512B/1024=64KB
- 二次间接容量=128×128×512B/1024
- 三次间接容量=128×128×128×512B/1024
- 超级块、索引区、数据块。超级块一般存位视图信息还有文件管理控制信息。
文件系统的重要数据结构
- 用户打开文件表:
- 进程的PCB结构中保留一个files_struct,称为用户打开文件表或文件描述符表,表项的序号为文件描述符fd,该登记项内登记系统打开文件表的一个入口指针fp,通过此系统打开文件表项连接到打开文件的活动inode。
- 系统打开文件表:
- 是为解决多用户进程共享文件、父子进程共享文件而设置的系统数据结构file_struct,主存专门开辟最多可登记256项的系统打开文件表区,当打开一个文件时,通过此表项把用户打开文件表的表项与文件活动inode联接起来,以实现数据的访问和信息的共享。
- 主存活动inode表:
- 为解决频繁访问磁盘索引节点inode表的效率问题,系统开辟的主存区,正在使用的文件的inode被调入主存活动索引节点inode中,以加快文件访问速度。
文件操作的实现
-
文件系统提供给用户程序的一组系统调用,包括:创建、删除、打开、关闭、读、写和控制,通过这些系统调用用户能获得文件系统的各种服务。
-
创建文件:
-
int fd, mode; char *filenamep; fd = create (filenamep, mode);
-
过程:
- 为新文件分配索引节点和活动索引节点
- 在新文件所对应的活动索引节点中置初值,如置存取权限i_mode,连接计数i_nlink。
- 分配用户打开文件表项和系统打开文件表项,置表项初值,读写位移f_offset清“0”
- 把各表项及文件对应的活动索引节点用指针连接起来,把文件描述字返回给调用者
-
-
删除文件:
- 删除把指定文件从所在的目录文件中除去。
- 如果没有连接用户(i_link 为“1”),还要把文件占用的存储空间释放。删除系统调用形式为:unlink (filenamep)。
-
打开文件:
-
int fd, mode; char * filenamep; fd = open (filenamep, mode);
-
过程:
- 把外存索引节点复制到活动索引节点表
- 根据参数mode核对权限,如果非法,则这次打开失败
- 当“打开”合法时,为文件分配用户打开文件表项和系统打开文件表项,并为表项设置初值。
- 通过指针建立这些表项与活动索引节点间的联系。把文件描述字,即用户打开文件表中相应文件表项的序号返回给调用者。
-
-
关闭文件:
-
int fd; close (fd);
-
过程:
- 根据fd找到用户打开文件表项,再找到系统打开文件表项。释放用户打开文件表项。
- 把对应系统打开文件表项中的f_count减“1”,如果非“0”,说明还有进程共享这一表项,不用释放直接返回;否则释放表项。
- 把活动索引节点中的i_count减“1”,若不为“0”,表明还有用户进程正在使用该文件,不用释放而直接返回,否则在把该活动索引节点中的内容复制回文件卷上的相应索引节点中后,释放该活动索引节点。
-
f_count和i_count分别反映进程动态地共享一个文件的两种方式
- f_count反映不同进程通过同一个系统打开文件表项共享一个文件的情况;
- i_count反映不同进程通过不同系统打开文件表项共享一个文件的情况。
- 通过两种方式,进程之间既可用相同的位移指针f_offset,也可用不同位移指针f_offset共享同一个文件。
-
-
读文件:
-
int nr, fd, count; char buf [ ] nr = read (fd, buf, count);
-
过程:
- 系统根据f_flag中的信息,检查读操作合法性,
- 再根据当前位移量f_offset值,要求读出的字节数,及活动索引节点中i_addr指出的文件物理块存放地址,把相应的物理块读到缓冲区中,然后再送到bufp指向的用户主存区中。
-
-
写文件:
-
nw = write (fd, buf, count); buf是信息传送的源地址,即把buf所指向的用户主存区中的信息,写入到文件中。
-
文件的符号链接共享
-
先说下硬链接共享的问题:
- 问题:系统中每个文件对应一个inode,编号是惟一的,但两个不同的磁盘或分区都含有相同inode号对应的文件,也就是说,整合的目录树中,inode号并不惟一地标识一个文件。
- 办法:拒绝创建跨越文件系统的硬链接。
-
符号链接又称软链接,是一种只有文件名,不指向inode的文件
- 实现:用户A目录中形式为afile→bfile,实现A的目录与B的文件的链接。其中只包含被链接文件bfile的路径名而不是它的inode号,而文件的拥有者才具有指向inode的指针 。
虚拟文件系统VFS
- 虚拟文件系统也称虚拟文件系统开关VFS (Virtual Filesystem Switch)
- 它是内核的一个子系统,提供一个通用文件系统模型,该模型概括所能见到的文件系统常用功能和行为,处理一切和底层设备驱动相关的细节,为应用程序提供标准的接口(文件系统API)。
- 同时支持多种文件系统
- 多个文件系统应与传统的单一文件系统没有区别,在用户面前表现为一致的接口
- 提供通过网络共享文件的支持,访问远程结点上的文件系统应与访问本地结点的文件系统一致
- 实现:
- 应用层:
- VFS模型源于UNIX文件系统,使得用户可直接使用标准UNIX文件系统调用来操作文件,无需考虑具体文件系统特性和物理存储介质,通过VFS访问文件系统,才使得不同文件系统之间的协作性和通用性成为可能。
- 虚拟层:
- 对所有具体文件系统的共同特性进行抽象的基础上,形成一个与具体文件系统实现无关的虚拟层,并在此层次上定义与用户的一致性接口;
- 实现层:
- 该层使用类似开关表技术进行具体文件系统转接,实现各种具体文件系统的细节,每一个是自包含的,包含文件系统实现的各种设施,如超级块、节点区、数据区以及各种数据结构和文件类的操作函数。
- 应用层:
硬链接与软链接区别 shell和应用程序中创建的命令
硬链接 | 软链接 |
---|---|
不同文件名对应同一个inode | 存储被链接文件的文件名(而不是inode)实现链接 |
不能跨越文件系统 | 可跨越文件系统 |
对应系统调用link | 对应系统调用symlink |
int link(const char *oldpath,const char *newpath) | int symlink(const char *oldpath,const char *newpath) |
ln source target | ln -s source target |
bootloader引导程序作用、两种引导程序
加载操作系统内核到内存并启动。
- LILO:依赖硬盘绝对地址来寻找映像
- GRUB:理解文件系统并寻找包含引导程序文件,配置文件/boot/grub/grub.conf