四塊知識一套賬:狀態(tài)遷移邊界與自檢框架)
簡介面向西北工業(yè)大學801考研的操作系統(tǒng)復習資料以單份PDF形式梳理課程核心知識適合基礎階段搭建知識框架也便于沖刺階段查漏補缺。內(nèi)容按操作系統(tǒng)概述、進程管理、內(nèi)存管理、文件管理、設備管理與作業(yè)調(diào)度六部分展開覆蓋進程狀態(tài)與PCB、先來先服務與短作業(yè)優(yōu)先等調(diào)度算法、同步互斥與PV操作、固定分區(qū)與分頁分段、虛擬內(nèi)存與內(nèi)外碎片、文件邏輯與物理結(jié)構、I/O控制方式及作業(yè)周轉(zhuǎn)時間等高頻考點并對易混概念和算法差異作出歸納便于對照教材建立復習索引。壓縮包內(nèi)共1個PDF文件大小約19.05MB內(nèi)容集中適合按章節(jié)檢索、在平板或電腦上閱讀標注并反復翻閱。已有167人學習可作為801專業(yè)課復習中的提綱式筆記與考前速覽材料幫助快速定位重點章節(jié)和薄弱環(huán)節(jié)。1. 四塊知識其實是一套賬操作系統(tǒng)考的從來不是概念而是狀態(tài)遷移的邊界翻過一份把操作系統(tǒng)壓成幾十頁的手寫掃描筆記最反直覺的地方在于進程、內(nèi)存、文件、設備看上去是四套獨立知識實際上卻對應同一套記賬邏輯——資源有狀態(tài)狀態(tài)只能沿合法邊界遷移考題和真實內(nèi)核出問題的地方都集中在邊界上。801 這類自命題科目真正愛考的是“進程在等 I/O 時被調(diào)度走誰保存了它當時的現(xiàn)場”這類問題而“什么是 PCB”這種表層問題并非重點。把這套賬理順之后需要背誦的內(nèi)容會減少一大半剩下的內(nèi)容基本都能自己推導出來。2. 進程與 PCB為什么“狀態(tài)”必須落進一個結(jié)構體里大多數(shù)人對進程的理解停留在“程序的一次執(zhí)行”這句話沒錯但幾乎不解決問題。真正讓人算錯題、也真正讓內(nèi)核寫出 bug 的是狀態(tài)機的邊和 PCB 的字段筆記如果只畫了五個方框和箭頭卻沒有說明哪條邊是誰觸發(fā)的后面調(diào)度、同步、死鎖就會全部只能靠背。這一章把這三樣拆開看狀態(tài)機的約束、PCB 的字段動機、調(diào)度算法的選擇函數(shù)。2.1 進程狀態(tài)機五條邊里只有兩條是進程自己走的從一個剛提交的作業(yè)到進程終止中間的狀態(tài)是新建、就緒、運行、等待、終止。就緒到運行由調(diào)度器決定運行到就緒是時間片用完或被更高優(yōu)先級搶占運行到等待由進程自己觸發(fā)典型場景是讀文件、等鎖、等 I/O 完成這類阻塞叫自愿阻塞等待到就緒由外部事件完成后喚醒運行到終止則是進程退出。最容易被畫錯的一條邊是“等待直接到運行”。這條邊不存在原因很直白被喚醒的進程只是重新具備了運行資格能不能拿到 CPU 得由調(diào)度器按策略決定。如果允許等待直接跳到運行等于事件完成的一瞬間強行搶占 CPU所有調(diào)度策略都會立刻失效優(yōu)先級、時間片、多級隊列全部作廢。內(nèi)核里喚醒的正確動作是“把 PCB 從等待隊列摘下、掛到就緒隊列”僅此而已。還有一個高頻混淆點阻塞和掛起不是一回事。阻塞是進程在內(nèi)存里等事件掛起是把進程映像換到外存、騰出內(nèi)存給別的進程用這才有了七狀態(tài)模型里的“就緒掛起”和“等待掛起”。做題時如果題目出現(xiàn)“內(nèi)存緊張”“換出”那考的是掛起只說“等待 I/O”那是阻塞。2.2 PCB內(nèi)核里唯一信得過的現(xiàn)場記錄進程切換的本質(zhì)是“把一套 CPU 寄存器換掉再把另一套裝進來”。CPU 只有一套物理寄存器被切走的進程的所有現(xiàn)場必須有個地方存這個地方就是 PCB它也是內(nèi)核態(tài)數(shù)據(jù)用戶態(tài)代碼碰不到。/* 極度簡化的 PCB 模型字段取自教科書常見劃分不代表任何真實內(nèi)核實現(xiàn) */ struct pcb { int pid; /* 進程標識隊列和表里的主鍵 */ int state; /* NEW/READY/RUNNING/WAITING/TERMINATED */ uint64_t pc; /* 程序計數(shù)器切走時下一條要執(zhí)行的指令地址 */ uint64_t regs[32]; /* 通用寄存器現(xiàn)場切換時整組保存/恢復 */ uint64_t pgtbl; /* 頁表基址這個進程地址空間的身份 */ int priority; /* 調(diào)度優(yōu)先級多級反饋隊列里會被動態(tài)改寫 */ struct pcb *next; /* 就緒/等待隊列指針決定入隊是 O(1) 還是 O(n) */ int exit_code; /* 退出碼留給父進程收尸 */ };逐個字段看動機。pc和regs是進程切換時的核心現(xiàn)場沒有它們進程被切走后回來就不知道執(zhí)行到哪了這就是操作系統(tǒng)的“后悔藥”。pgtbl決定了切換的代價量級同一地址空間內(nèi)的線程切換不用換它進程切換要換而換頁表往往伴隨 TLB 失效。next指針是純粹的數(shù)據(jù)結(jié)構選擇用鏈表就是 O(1) 入隊但調(diào)度時要遍歷找優(yōu)先級最高的用優(yōu)先級數(shù)組或多級隊列則是 O(1) 選人但可能浪費內(nèi)存。priority是唯一一個“策略會反過來改數(shù)據(jù)結(jié)構”的字段老化機制就是不停給它減分。為什么 PCB 必須放在內(nèi)核態(tài)、用戶不可寫道理和虛擬內(nèi)存是同一個如果進程能改自己的state或pgtbl隔離就徹底不存在了。PCB 就是內(nèi)核記錄進程狀態(tài)的唯一可信位置所有系統(tǒng)調(diào)用最終都會修改它。2.3 調(diào)度算法同一個循環(huán)換一個 pick 函數(shù)把教材里那一堆 FCFS、SJF、優(yōu)先級、多級反饋隊列攤開看它們的骨架完全一樣一個循環(huán)每次從就緒集合里挑一個進程讓它跑跑完或被打斷再挑。區(qū)別只在“怎么挑”以及“能不能打斷”。from dataclasses import dataclass dataclass class Proc: pid: str arrive: int # 到達時刻進入就緒隊列的時間 burst: int # 需要占用 CPU 的時間 def schedule(procs, pick): pick: 從當前就緒集合里選出下一個執(zhí)行的進程 非搶占模型選中后一次跑完整個 burst 返回 [(pid, 周轉(zhuǎn)時間, 帶權周轉(zhuǎn)時間), ...] t, ready, rest, out 0, [], sorted(procs, keylambda p: p.arrive), [] while rest or ready: while rest and rest[0].arrive t: # 把已到達的放進就緒隊列 ready.append(rest.pop(0)) if not ready: # CPU 空轉(zhuǎn)時間跳到下一個到達點 t rest[0].arrive continue p pick(ready) ready.remove(p) t p.burst # 非搶占一次跑完 turnaround t - p.arrive out.append((p.pid, turnaround, turnaround / p.burst)) return out # FCFS誰先來誰先跑pick 只看到達時間 fcfs lambda q: min(q, keylambda p: p.arrive) # SJF誰短誰先跑pick 只看服務時間 sjf lambda q: min(q, keylambda p: p.burst)參數(shù)含義需要說清arrive決定就緒隊列的入隊時機burst是服務時間周轉(zhuǎn)時間是“完成時刻減到達時刻”帶權周轉(zhuǎn)時間是“周轉(zhuǎn)時間除以服務時間”分母弄錯是考場上最常見的失分點。把pick換成max就是優(yōu)先級調(diào)度換成“剩余時間最短”并允許打斷就是 SRTF。三種策略的設計動機值得逐條說。FCFS 最簡單、天然公平但有護航效應一個長作業(yè)排在隊首后面所有短作業(yè)都要干等平均周轉(zhuǎn)時間會大幅增加。SJF 能證明平均周轉(zhuǎn)時間最小代價是它要求預知burst而現(xiàn)實中沒人知道下一個進程要跑多久工程上的做法是用指數(shù)平滑預測把上一次的預測值和這次的實際值加權混合權重越小越保守。就算預測準了SJF 還會餓死長作業(yè)所以優(yōu)先級調(diào)度必須配老化等待越久優(yōu)先級越高用一點最優(yōu)性換無饑餓。多級反饋隊列是這三種思路的折中方案也是我認為最值得琢磨的設計新進程進最高優(yōu)先級隊列給一個很短的第一個時間片用完沒結(jié)束就降到下一級時間片變長一直降到最低級。它不需要預測運行時間卻能用“降級”近似出 SJF 的效果因為短作業(yè)在第一級就跑完了長作業(yè)自動沉底。代價是兩個參數(shù)沒法從理論上定隊列級數(shù)和每級時間片長度都是靠測量調(diào)出來的這也是它經(jīng)常被吐槽為“玄學”的原因。2.4 上下文切換真正貴的是冷卻不是保存很多人默認進程切換昂貴、線程切換廉價然后拿這句話去解釋所有性能問題。這句話只在特定前提下成立。直接開銷是保存恢復寄存器、切換內(nèi)核棧、更新 PCB 狀態(tài)這部分對進程和線程差不多量級很小。真正的差距在地址空間進程切換要換頁表基址TLB 里緩存的地址翻譯全部作廢Cache 里的數(shù)據(jù)也大面積失效回到用戶態(tài)后要重新預熱。我一般會這么理解切換成本由“換不換地址空間”決定不由“是不是線程”決定。同一個進程里兩個線程如果跑在不同核上、訪問的數(shù)據(jù)八竿子打不著Cache 該失效還是失效反過來如果兩個進程共享大量內(nèi)存頁切換后的預熱代價也沒那么夸張??吹健岸嚅_線程更快”這種結(jié)論先問一句快在哪是切換省了還是并發(fā)度上去了。3. 虛擬內(nèi)存為什么邏輯地址必須和物理地址解耦分頁這件事教材上一句話就能說完把邏輯地址空間切成固定大小的頁映射到物理頁框。但真正理解了以后你會發(fā)現(xiàn)虛擬內(nèi)存解決的從來不是“內(nèi)存不夠”而是三個更棘手的問題進程之間不能互相踩內(nèi)存、程序不能依賴自己被加載到哪個物理位置、內(nèi)存可以比物理內(nèi)存小。這一章沿著一次地址翻譯的全過程走把頁表項、缺頁、置換算法串起來。3.1 一次地址翻譯的完整旅程CPU 執(zhí)行一條訪存指令發(fā)出的是邏輯地址。MMU 把它切成兩部分低位是頁內(nèi)偏移高位是頁號。先查 TLB命中就直接拼出物理地址發(fā)到總線上沒命中就去查頁表多級頁表要一級一級往下走每一級都取一次內(nèi)存如果最后拿到的頁表項有效位是 0觸發(fā)缺頁異??刂茩嘟唤o內(nèi)核。舉一個能落地的例子32 位地址、頁大小 4KB。4KB 等于 2 的 12 次方所以低 12 位是頁內(nèi)偏移剩下 20 位是頁號。要是用兩級頁表每級 10 位一個地址0x00403A20拆出來就是一級索引0x001、二級索引0x003、偏移0xA20。十六進制下這個拆分特別好做頁大小 4KB 時最后三位十六進制數(shù)字就是偏移前面全是頁號考場上不用換算成二進制。多級頁表的設計動機常被講成“節(jié)省空間”其實更準確的說法是應對稀疏地址空間。單級頁表要給 20 位頁號建 2 的 20 次方個表項每項 4 字節(jié)就是 4MB每個進程一份而且這 4MB 必須常駐可一個進程實際用到的地址往往只集中在幾個區(qū)域中間大片是空的。兩級頁表把一級頁表壓到 4KB二級頁表按需創(chuàng)建沒用到的那段地址連二級頁表都不用建。注意多級頁表省的是空間代價是時間。一次 TLB 未命中可能要訪存兩次甚至四次這也是 TLB 命中率對性能影響這么大的原因。3.2 頁表項里每一位在干什么頁表項不是只存一個物理頁框號它是一組標志位加一個編號。有效位表示這一頁是否在內(nèi)存里為 0 就觸發(fā)缺頁保護位標記這一頁可讀、可寫還是可執(zhí)行寫一個只讀頁會觸發(fā)保護異常而不是缺頁這兩類異常的處理路徑完全不同修改位臟位表示這一頁被寫過沒有它決定了換出時要不要寫回磁盤這是純性能優(yōu)化沒寫過就不用寫回訪問位表示這一頁最近被訪問過它是 Clock 置換算法的唯一輸入。這幾位里臟位的性價比最高。操作系統(tǒng)在頁面換出時如果臟位是 0直接把頁框回收就行臟位是 1就得先寫磁盤再回收一次 I/O 的時間夠 CPU 跑幾十萬條指令。所以“讀多寫少”的映射文件、代碼段換出成本遠低于被頻繁寫的堆內(nèi)存。3.3 LRU 為什么在硬件里做不出來Clock 怎么近似理論上最優(yōu)的置換算法是換掉未來最久不會被訪問的那一頁這顯然無法實現(xiàn)退一步換掉過去最久沒被訪問的那頁就是 LRU。LRU 在軟件里好寫在硬件里幾乎做不了它要求每次訪存都更新時間戳或調(diào)整鏈表這個開銷比訪存本身還大而且要在 MMU 里實現(xiàn)沒法靠編譯器優(yōu)化。硬件只能提供一個訪問位。Clock 算法就把所有頁框串成一個環(huán)配一個指針需要換頁時看指針指向的頁訪問位是 1 就清成 0 并跳過是 0 就選它換出。這個“給一次免死機會”的動作本質(zhì)是用一個 bit 近似“最近有沒有被訪問”工程上夠用。from collections import OrderedDict def fifo(refs, frames): q, faults [], 0 for r in refs: if r not in q: faults 1 if len(q) frames: q.pop(0) # 淘汰最早進來的頁 q.append(r) return faults def lru(refs, frames): q, faults OrderedDict(), 0 for r in refs: if r in q: q.move_to_end(r) # 命中刷新為“最近使用” else: faults 1 if len(q) frames: q.popitem(lastFalse) # 淘汰最久未使用 q[q.__len__()] r if False else None q[r] None return faults refs [1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5] print(fifo(refs, 3), fifo(refs, 4)) # 9 10幀數(shù)變多缺頁反而增加 print(lru(refs, 3), lru(refs, 4)) # 10 8棧式算法不會反常這段代碼里refs是頁面訪問序列frames是可用頁框數(shù)返回值是缺頁次數(shù)。fifo用一個普通列表模擬先進先出隊列l(wèi)ru用OrderedDict維護訪問順序命中就move_to_end挪到隊尾淘汰時彈隊頭。第三行輸出就是著名的 Belady 異常FIFO 在 4 個頁框時缺頁次數(shù)比 3 個頁框還多。原因是 FIFO 不滿足“棧式算法”性質(zhì)增加頁框會改變整個淘汰歷史可能剛好把后面要用的頁提前踢掉。LRU 和最優(yōu)算法都是棧式的小容量的駐留集永遠是大容量的子集所以不會出現(xiàn)這種反常。這也是為什么教材強調(diào)這個反例它說明“加內(nèi)存一定變快”這種直覺在置換策略上是站不住的。3.4 內(nèi)碎片和外碎片分頁為什么沒有外碎片分頁的代價是內(nèi)部碎片進程最后一頁大概率裝不滿平均浪費半頁。但分頁完全沒有外部碎片因為所有頁框大小一致任意空閑頁框都能裝任意頁不存在“洞太小塞不進去”的情況。分段正好相反段是邏輯單位長度由程序決定一段代碼、一段數(shù)據(jù)、一個棧大小參差不齊。分配久了就會在內(nèi)存里留下大量小空洞總量夠但拼不出一個連續(xù)的大段這就是外部碎片解決辦法是緊湊把進程整體挪動把空洞擠到一起代價是搬運開銷。段頁式是兩者的組合先按邏輯分成段每段再分頁邏輯結(jié)構保住了物理分配也整齊了代價是一次訪存要查段表再查頁表地址翻譯路徑更長。頁大小 4KB 是一個經(jīng)典的折中頁太小則頁表項數(shù)量爆炸、TLB 能覆蓋的范圍變小頁太大則內(nèi)碎片浪費加劇、一次缺頁要讀的數(shù)據(jù)變多。這個數(shù)值不是理論最優(yōu)而是幾十年工程實踐調(diào)出來的平衡點。4. 文件與設備索引、緩存、調(diào)度其實是同一套思路換了對象文件管理和設備管理常被當成兩塊邊緣內(nèi)容其實它們是前面兩章的復用文件就是“用索引結(jié)構管理外存塊”設備管理就是“用隊列和調(diào)度管理獨占資源”。把 inode 看懂把 DMA 和磁盤調(diào)度的動機搞清這部分幾乎不用背。4.1 inode文件就是一張索引表加一個編號目錄里存的不是文件內(nèi)容而是“文件名到 inode 號”的映射。inode 里放元數(shù)據(jù)大小、所有者、權限、時間戳和塊地址。關鍵是塊地址的組織方式前若干個是直接塊后面跟一級間接、二級間接、三級間接。間接塊本身不存數(shù)據(jù)只存下一層塊的編號。def max_file_bytes(block4096, ptr4, n_direct12): block : 磁盤塊大小字節(jié) ptr : 一個塊地址占多少字節(jié)決定每個間接塊能裝多少指針 n_direct: 直接塊數(shù)量 返回最大文件字節(jié)數(shù)與各級間接的容量明細 per_block block // ptr # 每個間接塊能放 1024 個指針 detail {direct: n_direct * block} total detail[direct] cap per_block for level in (1, 2, 3): cap * per_block if level 1 else per_block ... return total, detail print(max_file_bytes())按 4KB 塊、4 字節(jié)指針算每個間接塊能放 1024 個指針。12 個直接塊覆蓋 48KB一級間接再覆蓋 1024 個塊也就是 4MB二級間接 1024 的平方個塊4GB三級間接 4TB。這組數(shù)字解釋了 inode 設計的取舍絕大多數(shù)文件很小直接塊命中一次尋址就拿到數(shù)據(jù)路徑最短少數(shù)大文件靠多級間接撐住容量代價是訪問最后一個塊要多讀幾次間接塊每一次都是實打?qū)嵉?I/O。這本質(zhì)上是“小文件快、大文件能裝”的折中而不是追求兩種都最優(yōu)。4.2 三種物理結(jié)構的取舍順序結(jié)構把文件放在連續(xù)塊上尋道最少、支持隨機訪問缺點是兩個外部碎片以及文件增長時后面可能沒位置了只能整體搬家。鏈接結(jié)構把文件切成塊用指針串起來沒有碎片、隨便增長但只能順序訪問想讀最后一塊得從頭走一遍而且指針占空間中間一個塊壞了整條鏈就斷。索引結(jié)構給每個文件配索引塊索引塊里存所有塊的地址隨機訪問和增長都支持代價是多了一層索引塊開銷小文件可能為了幾百字節(jié)專門占一個索引塊。FAT 是鏈接結(jié)構的一個變體把整條鏈的指針集中到內(nèi)存里的一張表尋道時查表就行本質(zhì)上是用內(nèi)存換訪問速度。這三種結(jié)構沒有絕對優(yōu)劣選哪個取決于“這個文件系統(tǒng)主要跑什么負載”日志類順序?qū)懚嘤面溄幼凅w數(shù)據(jù)庫類隨機讀多用索引。4.3 空閑空間管理位圖與成組鏈接位圖用 1 bit 標記一個塊是否被占用查找連續(xù)的空閑塊特別快因為連續(xù)的 bit 可以一次掃描一大片。代價是占空間1TB 磁盤、4KB 塊一共 2 億多個塊位圖就是 32MB 左右這部分通常常駐內(nèi)存??臻e鏈表把空閑塊本身串成鏈幾乎不額外占空間但想找一段連續(xù)空間就得遍歷。成組鏈接是折中方案把空閑塊按組串起來每組的第一塊記錄下一組的塊號和數(shù)量分配時一次能拿到一批既省空間又不用全程遍歷。這幾種方案的取舍都能用一句話概括拿空間換查找速度還是拿查找速度換空間。4.4 DMA 到底省了什么磁盤調(diào)度又在省什么I/O 控制方式有三種。程序查詢是 CPU 死等設備就緒全程占用處理器中斷驅(qū)動是設備準備好一個字節(jié)就中斷一次CPU 每次都參與數(shù)據(jù)搬運好處是不用空轉(zhuǎn)DMA 是 CPU 只發(fā)一條命令把內(nèi)存地址、傳輸長度告訴控制器剩下的搬運由控制器直接和內(nèi)存打交道全部傳完才中斷一次。這里的常見誤解是把 DMA 當成“讓磁盤變快”。DMA 省的是 CPU 搬運數(shù)據(jù)的時間磁盤本身的機械尋道一點沒變快。區(qū)分這兩件事很重要I/O 響應時間由磁盤決定CPU 占用率由控制方式?jīng)Q定題目問哪個就答哪個。磁盤調(diào)度才是真正在減少尋道。FCFS 按請求順序服務公平但平均尋道距離大SSTF 每次選離當前磁頭最近的請求平均尋道最短但遠端請求可能永遠等不到SCAN 像電梯一樣單向掃到端點再折返犧牲一點平均尋道換無饑餓。拿一組真實可算的數(shù)字對比磁頭當前在 100 磁道請求序列是 55、58、39、18、90、160、150、38、184。SSTF 的走法是 100→90→58→55→39→38→18→150→160→184總移動 248 個磁道。SCAN 假設向大號方向掃走法是 100→150→160→184→199→90→58→55→39→38→18總移動 280 個磁道。有意思的是這里 SCAN 反而更差。這不是算錯而是它揭示了 SCAN 的真實定位它優(yōu)化的是“最大等待時間”和“響應方差”不是總移動距離。回程那 109 個磁道是白跑的但正因為掃到端點遠處的請求有一個可預期的等待上界。題目如果問“平均尋道長度最短”答案是 SSTF問“不會饑餓”答案才輪到 SCAN。5. 排查清單五類“看著會、一做就錯”的翻車現(xiàn)場復習到后期卡住人的往往不是不懂而是懂了個大概然后在細節(jié)上翻車。下面五條是這類筆記里反復出現(xiàn)、也最容易在考場上丟分的地方每條按現(xiàn)象、原因、解決三段寫。5.1 同步與互斥PV 寫反與初值給錯第一條現(xiàn)象是 PV 操作能默寫出來但推出執(zhí)行序列時發(fā)現(xiàn)兩個進程互相等待。原因幾乎都是 P 操作的順序問題一個進程先 P 互斥量再 P 資源量另一個進程占著資源等互斥量雙方各持一把鎖不放手。解決辦法是記住固定順序先 P 資源信號量、再 P 互斥信號量V 操作順序反過來?;コ饬恐槐Wo臨界區(qū)資源量才代表“有沒有東西可用”先拿資源再進臨界區(qū)邏輯上就不可能死鎖。第二條現(xiàn)象是生產(chǎn)者消費者寫出來以后兩個進程變成完全串行一點并發(fā)都沒有。原因是把緩沖區(qū)計數(shù)當成了互斥量empty和full的初值給成了 1?;コ庑盘柫砍踔当仨毷?1表示臨界區(qū)只有一個入口empty的初值是緩沖區(qū)容量full的初值是 0它們代表的是資源數(shù)量而不是鎖。初值給錯整個同步關系就退化成了互斥。5.2 計算題地址、時間、磁道三個易錯位第三條現(xiàn)象是頁號頁內(nèi)偏移算出來跟答案差一位。原因是頁大小和位數(shù)的換算沒做熟4KB 就是 2 的 12 次方偏移 12 位十六進制下正好是末三位。解決辦法是養(yǎng)成習慣見到十六進制地址先數(shù)末三位當偏移前面的當頁號見到十進制就先除以頁大小取整得頁號余數(shù)就是偏移別在腦子里做二進制拆分。第四條現(xiàn)象是帶權周轉(zhuǎn)時間算出來比 1 還小。原因是分母寫成了等待時間或周轉(zhuǎn)時間。帶權周轉(zhuǎn)時間的定義是周轉(zhuǎn)時間除以服務時間服務時間是進程真正占用 CPU 的時長任何進程的這個比值都不會小于 1一旦算出小于 1立刻回頭檢查分母。第五條現(xiàn)象是磁盤調(diào)度總移動道數(shù)比標準答案少一截。原因是從 0 號磁道或者第一個請求開始算的。磁頭有一個初始位置所有移動都必須從當前位置起算用 SCAN 還要記得算到端點比如 199 號磁道的那一段這段路雖然不服務任何請求但它真實發(fā)生了。做題時先把磁頭位置和請求序列抄在草稿紙最上面畫一條數(shù)軸標出來比在腦子里空想靠譜得多。6. 從“記住結(jié)論”到“能自己推”一套可驗證的自檢模型這份筆記真正有用的地方不在于它把五章內(nèi)容壓成了幾十頁而在于它給出了一套可以反復自檢的框架。我在看這類材料時習慣把每一章都壓縮成三個問題這個資源有哪幾個狀態(tài)誰有權改這些狀態(tài)改一次的代價是什么。進程那一章狀態(tài)是就緒、運行、等待改狀態(tài)的是調(diào)度器和進程自己代價是上下文切換內(nèi)存那一章狀態(tài)是頁在不在內(nèi)存、臟不臟改狀態(tài)的是缺頁處理和置換算法代價是一次磁盤 I/O文件那一章狀態(tài)是塊分配了沒有、索引到不到位改狀態(tài)的是文件系統(tǒng)和緩存代價是尋道加傳輸。這三個問題的價值在于它把“背結(jié)論”變成了“推結(jié)論”。比如頁大小為什么是 4KB按這個框架推頁小則頁表項多、TLB 覆蓋范圍小、缺頁頻繁頁大則內(nèi)碎片多、一次缺頁搬運的數(shù)據(jù)多。兩邊都有代價所以只能取中間值具體數(shù)字是工程調(diào)出來的但“為什么必須折中”是可以推的。同理索引結(jié)構為什么要有直接塊和三級間接也是同一個推法。驗證方法也很樸素拿一個具體例子手算一遍再和筆記對照。算一道 SJF 的周轉(zhuǎn)時間算一次兩級頁表的地址拆分算一遍 SCAN 的磁道總數(shù)手算過的東西和看過的東西在考場上完全是兩個狀態(tài)。我吃過這個虧筆記看得滾瓜爛熟一到手算地址翻譯就卡在十六進制換位上那道題的分丟得毫無技術含量。從那以后我每次看這類知識點梳理都會強迫自己先合上筆記把狀態(tài)遷移圖畫一遍、把關鍵參數(shù)算一遍再翻回去對答案對不上的地方才是真正要補的洞。希望幫到你。本文還有配套的精品資源點擊獲取