1. 备考中级软件评测师,操作系统这块到底该怎么啃
如果你正在准备中级软件评测师考试,操作系统这一章大概率是你绕不过去的一道坎。我当初备考的时候,翻遍了大半个互联网,发现一个很尴尬的事:网上关于操作系统的资料要么是考研级别的深奥理论,要么是零散到不成体系的碎片笔记,真正针对软考中级评测师这个考试层次、能把考点和实际理解结合起来的资料,少得可怜。后来我花了将近两个月时间,把操作系统这一块从头到尾梳理了一遍,整理出了一套自己的备考笔记,最终也顺利通过了考试。这篇文章就是把我当时整理的思路、重点、踩过的坑,以及一些记忆技巧全部摊开来聊。
操作系统在软件评测师考试里占的分值不算特别高,但它的特点是概念密集、容易出选择题、偶尔在大题里也会涉及性能分析相关的内容。很多考生觉得操作系统就是背一背,其实不是。如果你不理解进程调度背后的逻辑,你做题的时候只能靠蒙;如果你搞不清楚死锁的四个必要条件,题目稍微换个说法你就选错了。所以我的核心思路是:先理解机制,再记忆结论,最后通过做题来验证和巩固。
这篇文章适合谁看?如果你正在备考中级软件评测师,对操作系统的概念还比较模糊,或者看了一遍书但做题正确率上不去,那这篇笔记应该能帮到你。如果你只是想了解一下操作系统的基础知识,这篇文章也能给你一个比较系统的框架。我会尽量用大白话把每个概念讲清楚,同时标注出考试中常见的出题角度和陷阱。
2. 操作系统考什么:先搞清楚考试范围和出题套路
2.1 软件评测师考试中操作系统的分值分布
很多人一上来就开始背书,连考试大纲都没仔细看过。我的建议是,先花半个小时把考试大纲里操作系统部分的要求读一遍,你会有一种“原来只考这些”的释然感。根据我自己的备考经验和历年真题的统计,操作系统在基础知识科目中通常占5到8分左右,在应用技术科目中偶尔会结合性能测试出1到2道小题。
具体来说,常考的知识模块包括:操作系统的基本概念和功能、进程管理(这是重中之重)、存储管理、文件管理、设备管理、作业管理。其中进程管理几乎每年必考,存储管理次之,文件管理和设备管理相对少一些但也不能完全放弃。
从题型来看,选择题主要考概念辨析和简单计算,比如给你一个进程调度算法让你算平均周转时间,或者给你一个页面置换算法的访问序列让你算缺页次数。大题里如果出现操作系统相关内容,通常是结合系统性能评测来考,比如分析某个系统的瓶颈是否与内存管理策略有关。
2.2 为什么进程管理是绝对的核心
我统计过近五年的真题,进程管理相关的题目占了操作系统总分的将近一半。为什么?因为进程管理是整个操作系统的灵魂,它涉及到CPU调度、并发控制、死锁处理、进程通信等核心机制,这些机制直接影响到系统的性能和稳定性,而软件评测师的核心工作就是评估系统的性能和质量。
进程管理里最常考的几个点:进程的状态转换(就绪、运行、阻塞之间的切换条件)、进程与线程的区别、调度算法(先来先服务、短作业优先、时间片轮转、优先级调度)、死锁的四个必要条件和处理方法、进程同步与互斥(信号量机制、PV操作)。这几个点你必须要做到看到题目就能条件反射地选出答案,不能有丝毫犹豫。
2.3 存储管理为什么容易丢分
存储管理是第二大考点,但也是很多考生容易丢分的地方。原因很简单:页面置换算法的计算题需要你一步一步手动模拟,稍不留神就算错了。常见的页面置换算法有OPT(最佳置换)、FIFO(先进先出)、LRU(最近最少使用)、CLOCK(时钟置换)等。考试里最常考的是FIFO和LRU,偶尔会考OPT用来做对比。
我当时的做法是:把每种算法的模拟过程练到形成肌肉记忆。具体来说,拿到一个访问序列,我能快速地在草稿纸上画出内存块的变化过程,然后数出缺页次数。这个能力没有捷径,就是反复练。我大概练了三十多道页面置换的题目,到后面基本上看到序列就能预判出缺页次数的大致范围。
3. 进程与线程:把最核心的概念吃透
3.1 进程到底是什么,用生活化的方式理解
书上对进程的定义是“程序在一个数据集合上运行的过程,是系统进行资源分配和调度的基本单位”。这个定义没毛病,但太抽象了。我自己的理解方式是这样的:程序就像是一份菜谱,进程就像是你按照菜谱在厨房里实际做菜的过程。菜谱是静态的,放在那里不会动;但做菜的过程是动态的,涉及到拿食材(分配内存)、用灶台(占用CPU)、看火候(等待IO)等等。
进程有几个关键特征:动态性(它是程序的一次执行过程)、并发性(多个进程可以同时存在于内存中)、独立性(每个进程有自己独立的地址空间)、异步性(进程按各自独立的不可预知的速度向前推进)。这几个特征在选择题里经常出现,尤其是“独立性”和“异步性”,容易和其他概念混淆。
进程的状态转换是必考内容。一个进程通常有三种基本状态:就绪态、运行态、阻塞态。就绪态是指进程已经具备了运行条件,只差CPU;运行态是指进程正在占用CPU执行;阻塞态是指进程因为等待某个事件(比如IO完成)而暂停执行。转换关系是这样的:就绪到运行是调度程序选中的结果,运行到就绪是时间片用完或被更高优先级进程抢占,运行到阻塞是进程主动请求某个资源而该资源不可用,阻塞到就绪是等待的事件发生了。
注意:阻塞态不能直接转到运行态,必须先经过就绪态。这个点在选择题里反复出现,很多人一紧张就选错了。
3.2 线程和进程的区别,考试到底怎么考
线程是进程内的一个执行单元,是CPU调度的基本单位。一个进程可以包含多个线程,这些线程共享进程的地址空间和资源,但每个线程有自己的程序计数器、寄存器和栈。
考试里常考的区别点我整理成了一张表,方便你对比记忆:
| 对比维度 | 进程 | 线程 |
|---|---|---|
| 基本单位 | 资源分配的基本单位 | CPU调度的基本单位 |
| 地址空间 | 独立地址空间 | 共享所属进程的地址空间 |
| 切换开销 | 较大,需要切换页表和上下文 | 较小,只需切换少量寄存器 |
| 通信方式 | 需要借助IPC机制 | 可直接读写共享变量 |
| 健壮性 | 一个进程崩溃不影响其他进程 | 一个线程崩溃可能导致整个进程崩溃 |
这张表你最好能默写出来。考试里经常出的一种题是:“下列关于进程和线程的说法,正确的是”,然后给你四个选项,每个选项都是对表中某个点的改写,有的是正确的,有的是把进程和线程的特性互换了。你只要把这张表记牢,这种题就是送分题。
3.3 进程通信的几种方式及适用场景
进程之间要交换数据,就需要进程通信机制。常见的几种方式:共享内存、消息传递、管道、信号量。每种方式有自己的适用场景和优缺点。
共享内存是最快的IPC方式,因为数据不需要在进程之间复制,多个进程直接映射同一块物理内存。但它的缺点是同步问题需要程序员自己处理,比如一个进程在写的时候另一个进程不能读,这就需要配合信号量来使用。
消息传递适合分布式环境,进程之间通过发送和接收消息来通信,不需要共享地址空间。它的缺点是性能不如共享内存,因为消息需要在内核和用户空间之间复制。
管道是一种半双工的通信方式,数据只能单向流动。匿名管道只能用于父子进程之间,命名管道可以用于任意两个进程之间。管道的好处是简单易用,缺点是容量有限,通常只有几KB到几十KB。
信号量主要用于进程同步和互斥,它本身不传递大量数据,而是用来控制对共享资源的访问。PV操作是信号量的核心,P操作是申请资源(信号量减1),V操作是释放资源(信号量加1)。考试里经常出PV操作的题目,让你分析某个并发场景下信号量的取值范围,或者判断某个操作序列是否会导致死锁。
4. 死锁:从四个条件到实际排查
4.1 死锁的四个必要条件,一个都不能少
死锁是指两个或多个进程在执行过程中,因争夺资源而造成的一种互相等待的现象,如果没有外力干预,这些进程都无法向前推进。死锁的产生必须同时满足四个条件:互斥条件、请求与保持条件、不可剥夺条件、循环等待条件。
互斥条件是指资源一次只能被一个进程使用。请求与保持条件是指进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源被其他进程占用,此时进程阻塞但对自己已获得的资源保持不放。不可剥夺条件是指进程已获得的资源在未使用完之前不能被强行剥夺。循环等待条件是指存在一个进程资源的循环等待链,链中每个进程都在等待下一个进程所持有的资源。
这四个条件只要破坏其中任何一个,死锁就不会发生。考试里常考的是:给你一个场景描述,让你判断是否可能发生死锁,或者问你破坏的是哪个条件。比如“系统规定所有进程必须按编号递增的顺序申请资源”,这破坏的就是循环等待条件。
4.2 死锁的处理策略:预防、避免、检测与解除
死锁的处理策略有四种:预防、避免、检测和解除。
预防是破坏四个必要条件中的一个或多个。比如破坏互斥条件很难,因为有些资源本身就是互斥的;破坏请求与保持条件可以要求进程一次性申请所有需要的资源;破坏不可剥夺条件可以在进程请求新资源失败时释放已持有的资源;破坏循环等待条件就是前面说的按序申请。
避免是在资源分配之前先判断这次分配是否会导致系统进入不安全状态。最著名的算法是银行家算法。银行家算法的核心思想是:系统在分配资源之前,先模拟分配后的状态,然后检查是否存在一个安全序列,使得所有进程都能顺利完成。如果存在安全序列,就分配;否则就等待。
检测与解除是允许死锁发生,但通过定期检测来发现死锁,然后采取措施解除。检测的方法通常是构建资源分配图,然后检查图中是否存在环路。解除的方法包括终止进程、剥夺资源、回滚等。
提示:银行家算法在考试里出现的频率不算特别高,但一旦出现就是大题,分值不低。建议把算法的执行过程至少手动模拟三遍,确保每一步都理解透彻。
4.3 实际工作中怎么排查死锁问题
虽然考试主要考理论,但如果你以后从事软件评测或运维相关工作,实际排查死锁的能力也很重要。我分享几个实际工作中常用的排查思路。
数据库死锁是最常见的。以MySQL为例,你可以通过SHOW ENGINE INNODB STATUS命令查看最近一次死锁的详细信息,包括涉及的事务、等待的锁、执行的SQL语句等。SQL Server的话可以用扩展事件或者跟踪标志来捕获死锁图。排查的时候重点关注:哪些事务在互相等待、每个事务持有什么锁、请求什么锁、执行的顺序是什么。
应用程序层面的死锁通常表现为线程互相等待对方持有的锁。Java应用可以通过jstack工具导出线程转储,然后搜索“deadlock”关键字,JVM会自动检测并报告死锁的线程和锁信息。Linux系统上可以用pstack或gdb来查看进程的调用栈,分析线程在等待什么资源。
排查死锁的核心思路就一条:找到谁在等谁。把等待关系画成一张有向图,如果图中存在环,那就是死锁。然后分析这个环是怎么形成的,是锁的申请顺序不一致,还是某个线程持有锁的时间过长,或者是锁的粒度太粗导致的。
5. 存储管理:从分区到页面置换的完整梳理
5.1 存储管理的基本概念和考试重点
存储管理是操作系统里另一个重头戏。考试主要考几个方面:内存分配方式(连续分配和离散分配)、虚拟内存的概念、页面置换算法、分段与分页的区别。
连续分配是指为一个进程分配一块连续的内存空间。它分为单一连续分配、固定分区分配、动态分区分配。动态分区分配又衍生出几种分配算法:首次适应、最佳适应、最坏适应、循环首次适应。这几种算法的特点和优缺点需要记清楚,考试里经常出对比题。
离散分配是指把一个进程分散地分配到内存的多个不连续区域。分页存储管理是把进程的逻辑地址空间分成若干个大小相等的页,把内存的物理地址空间分成若干个大小相等的块(页框),页和页框一一对应。分段存储管理是按照程序的逻辑结构来划分,比如代码段、数据段、堆栈段等。段页式是两者的结合,先分段再分页。
虚拟内存是考试的高频考点。它的核心思想是:程序不需要全部装入内存就可以运行,只需要装入当前需要的部分,其余部分留在磁盘上,需要的时候再调入。虚拟内存的实现需要硬件支持,主要是页表机制和缺页中断机制。
5.2 页面置换算法的手动模拟技巧
页面置换算法是存储管理里最容易出计算题的地方。我总结了一套手动模拟的方法,可以帮你快速准确地算出缺页次数。
以LRU算法为例,假设访问序列是:7, 0, 1, 2, 0, 3, 0, 4,内存块数量为3。模拟过程如下:
第一步,7调入,内存:[7],缺页1次。 第二步,0调入,内存:[7, 0],缺页2次。 第三步,1调入,内存:[7, 0, 1],缺页3次。 第四步,2调入,内存满了,需要置换。LRU看最近最少使用的,7最久没用过,替换7,内存:[2, 0, 1],缺页4次。 第五步,0已在内存中,命中,更新0的使用时间,内存:[2, 0, 1]。 第六步,3调入,内存满了,1最久没用过,替换1,内存:[2, 0, 3],缺页5次。 第七步,0已在内存中,命中。 第八步,4调入,内存满了,2最久没用过,替换2,内存:[4, 0, 3],缺页6次。
最终缺页6次。这个模拟过程的关键是:每次命中时要更新该页的“最近使用时间”,每次置换时选择最久未被使用的页。我建议你在草稿纸上画一个表格,每一列是一次访问,每一行是一个内存块,这样不容易出错。
FIFO算法更简单,就是先进先出,替换最早进入内存的页。但FIFO有一个奇怪的现象叫Belady异常,就是增加内存块数量反而导致缺页次数增加。这个现象在考试里经常被拿来出题,问你哪种算法可能出现Belady异常,答案就是FIFO。
5.3 分页和分段的区别,用一张表说清楚
分页和分段是两种不同的离散分配方式,考试里经常考它们的区别。我整理了一张对比表:
| 对比维度 | 分页 | 分段 |
|---|---|---|
| 划分依据 | 物理单位,大小固定 | 逻辑单位,大小可变 |
| 对用户可见性 | 不可见,由系统管理 | 可见,用户编程时使用 |
| 地址空间 | 一维地址空间 | 二维地址空间(段号+段内偏移) |
| 信息共享 | 不方便共享 | 方便共享和保护 |
| 碎片类型 | 内部碎片 | 外部碎片 |
分页对用户是不可见的,用户感觉不到自己的程序被分成了页。分段对用户是可见的,用户编程时就需要指定段号。分页的地址是一维的,你只需要给出一个逻辑地址,系统自动拆分页号和页内偏移。分段的地址是二维的,你需要给出段号和段内偏移。
信息共享方面,分段比分页更方便,因为段是按逻辑结构划分的,一个函数或一个数据段可以单独共享。分页的话,一个函数可能跨越多个页,共享起来比较麻烦。
6. 文件管理和设备管理:容易被忽视但也会考
6.1 文件的逻辑结构和物理结构
文件管理这部分,考试主要考文件的逻辑结构和物理结构。逻辑结构是从用户角度看文件是怎么组织的,分为流式文件和记录式文件。流式文件就是一堆字节流,没有结构;记录式文件是由一条条记录组成,记录又分为定长和变长。
物理结构是从存储角度看文件在磁盘上是怎么存放的,分为连续结构、链接结构、索引结构。连续结构是把文件存放在磁盘上连续的一块区域,优点是读写快,缺点是容易产生外部碎片,文件扩展困难。链接结构是把文件分散存放在磁盘的多个块中,每个块包含指向下一个块的指针,优点是没有外部碎片,缺点是只能顺序访问,指针占用空间。索引结构是为每个文件建立一个索引表,索引表中存放文件各个块的地址,优点是支持随机访问,缺点是指针占用空间。
考试里常考的是这几种结构的优缺点对比,以及给定一个文件大小和块大小,计算需要多少个索引块或者多少级索引。比如一个文件有1000个块,每个索引块可以存放256个地址,那一级索引只能管理256个块,不够,需要两级索引,第一级索引指向第二级索引块,第二级索引块再指向数据块。
6.2 磁盘调度算法:FCFS、SSTF、SCAN、C-SCAN
磁盘调度算法是设备管理里的重点。常见的算法有:先来先服务(FCFS)、最短寻道时间优先(SSTF)、扫描算法(SCAN,也叫电梯算法)、循环扫描算法(C-SCAN)。
FCFS就是按请求到达的顺序依次处理,公平但效率低。SSTF是优先处理离当前磁头最近的请求,效率高但可能导致远处的请求饥饿。SCAN是磁头朝一个方向移动,沿途处理所有请求,到达最远端后反向移动。C-SCAN是只朝一个方向扫描,到达最远端后直接回到起点重新扫描,这样各个位置的请求等待时间更均匀。
考试里常考的是给你一个磁道请求序列和初始磁头位置,让你计算总寻道长度。计算的时候注意SCAN算法在到达最远端后是否要算上返回的寻道距离,这个细节容易出错。我的经验是:SCAN算法通常只计算单向的寻道距离,但有些教材会把返回的距离也算上,做题时看清楚题目要求。
6.3 设备管理中的缓冲技术和SPOOLing技术
缓冲技术是为了解决CPU和IO设备速度不匹配的问题。缓冲区可以分为单缓冲、双缓冲、多缓冲和缓冲池。单缓冲是CPU和IO设备交替使用缓冲区,双缓冲是CPU和IO设备可以同时使用两个缓冲区,效率更高。
SPOOLing技术(假脱机技术)是用磁盘上的一个区域来模拟脱机输入输出,主要用于打印机共享。它的核心思想是:当多个进程同时请求打印机时,系统并不直接把打印机分配给某个进程,而是把打印数据写入磁盘上的一个队列,然后由后台进程依次从队列中取出数据发送给打印机。这样每个进程都感觉自己独占了打印机,实际上是共享的。
考试里SPOOLing技术经常和缓冲技术一起考,问你SPOOLing系统由哪些部分组成(输入井、输出井、输入进程、输出进程),或者问你SPOOLing技术提高了什么性能(提高了IO速度,实现了设备共享)。
7. 常见问题与排查技巧实录
7.1 备考过程中最容易踩的五个坑
我在备考过程中踩过不少坑,这里分享五个最常见的,希望能帮你少走弯路。
第一个坑:只背书不做题。操作系统的概念确实需要记忆,但光背不做题,你根本不知道考试会怎么考。我的建议是每看完一章就做对应的真题,做完之后把错题整理出来,分析错的原因。
第二个坑:忽视计算题的练习。页面置换、磁盘调度、银行家算法这些计算题,你看书的时候觉得懂了,但真正动手算的时候才发现各种细节容易出错。必须动手练,练到不假思索就能算对。
第三个坑:混淆相似概念。比如进程和线程、分页和分段、死锁和饥饿、缓冲和缓存,这些概念容易混淆,考试里经常拿来出辨析题。我的做法是把这些相似概念整理成对比表,反复看,直到能脱口而出它们的区别。
第四个坑:忽略PV操作的练习。PV操作是进程同步的核心,也是考试里容易出大题的地方。很多人觉得PV操作难,其实就是没有掌握分析方法。我的经验是:先确定哪些是互斥资源,哪些是同步关系,然后为每个互斥资源设置一个信号量,为每个同步关系设置一个信号量,最后写出各个进程的PV操作序列。
第五个坑:考前突击。操作系统这一章内容多、概念杂,考前突击根本来不及。最好在备考初期就把这一章过一遍,然后在中后期反复复习。
7.2 考场上的答题技巧
选择题遇到不确定的,先用排除法去掉明显错误的选项,然后在剩下的选项里选一个最符合题意的。操作系统的选择题很多时候考的是“最准确”的说法,而不是“正确”的说法,所以要注意选项之间的细微差别。
计算题一定要在草稿纸上一步一步写清楚,不要跳步。页面置换的题目,建议画表格;磁盘调度的题目,建议画磁道示意图;银行家算法的题目,建议画资源分配表。写清楚步骤还有一个好处:即使最后答案算错了,步骤分也能拿到一些。
大题如果涉及操作系统,通常是结合系统性能分析来考。答题的时候要注意把操作系统层面的原因和性能表现联系起来。比如问你“系统响应时间变长可能是什么原因”,你可以从进程调度策略、内存不足导致频繁换页、死锁导致进程阻塞等角度来分析。
7.3 常见问题速查表
| 问题 | 可能原因 | 排查思路 |
|---|---|---|
| 进程无法结束,提示拒绝访问 | 进程处于内核态不可中断,或存在父子进程依赖 | 检查进程状态,先结束父进程再结束子进程 |
| 系统卡顿,CPU占用高 | 进程死循环、频繁上下文切换、死锁 | 用top或任务管理器查看CPU占用,分析线程栈 |
| 内存显示不足 | 内存泄漏、缓存占用、虚拟内存配置不当 | 检查进程内存占用,分析是否有泄漏 |
| 数据库死锁 | 事务互相等待对方持有的锁 | 查看数据库死锁日志,分析事务执行顺序 |
| 磁盘IO瓶颈 | 频繁读写、磁盘碎片、RAID配置不当 | 用iostat分析IO情况,检查磁盘健康状态 |
这张表里的问题都是实际工作中经常遇到的,虽然考试不一定直接考,但理解这些问题背后的操作系统原理,对你做题和实际工作都有帮助。
8. 一些个人的备考体会
操作系统这一章,我前前后后复习了三轮。第一轮是通读教材,把所有的概念都过一遍,不求甚解,只求有个印象。第二轮是精读,把每个重点概念都吃透,配合做题来验证。第三轮是查漏补缺,把错题和容易混淆的概念再巩固一遍。
我觉得最有用的方法是“讲给别人听”。当你尝试把一个概念用自己的话讲清楚的时候,你才会发现自己哪里没理解透。我当时找了一个也在备考的朋友,我们每周互相讲一章的内容,讲不清楚的地方就回去重新看书。这个方法虽然花时间,但效果非常好。
还有一点:不要被那些看起来很复杂的计算题吓到。页面置换、磁盘调度、银行家算法这些,本质上都是按照固定规则一步步执行的过程,你只要把规则记清楚,然后耐心地一步步模拟,就一定能算对。我一开始也觉得这些题很难,但练了三十多道之后,发现套路其实很固定。
最后分享一个记忆技巧:把操作系统想象成一个城市的交通管理系统。进程是路上的车辆,CPU是路口信号灯,内存是停车场,磁盘是仓库,死锁是十字路口的堵死。你用这个类比去理解各种机制,会比死记硬背容易得多。比如进程调度就是信号灯决定哪辆车先走,页面置换就是停车场满了要挪走哪辆车,死锁就是四辆车在十字路口互相等着对方先走。这个类比不一定严谨,但能帮你快速建立起直观的理解。