干貨:軟件運(yùn)行機(jī)制及OS內(nèi)存管理


內(nèi)容選自:《許式偉的架構(gòu)課》
更多極客時(shí)間:架構(gòu)師技術(shù)專欄內(nèi)容請(qǐng)參看:
操作系統(tǒng)是怎么獲得執(zhí)行權(quán)的?這是計(jì)算機(jī)主板 ROM 上的啟動(dòng)程序(BIOS)交給它的。
計(jì)算機(jī)加電啟動(dòng)后,中央處理器(CPU)會(huì)從一個(gè)固定的存儲(chǔ)地址加載指令序列執(zhí)行。通常,這個(gè)固定的存儲(chǔ)地址指向計(jì)算機(jī)主板的 ROM 上的一段啟動(dòng)程序(BIOS)。這段啟動(dòng)程序通常包含以下這些內(nèi)容。
引導(dǎo)區(qū)的引導(dǎo)程序有長(zhǎng)度限制(關(guān)于這一點(diǎn)我在上一節(jié)已經(jīng)介紹過(guò)),只能做非常少的事情。在常規(guī)情況下,它只是簡(jiǎn)單地跳轉(zhuǎn)到真正的操作系統(tǒng)的啟動(dòng)程序,但有時(shí)計(jì)算機(jī)上安裝了多個(gè)操作系統(tǒng),此時(shí)引導(dǎo)程序會(huì)提供菜單讓你選擇要運(yùn)行的操作系統(tǒng)。
這樣,操作系統(tǒng)就開(kāi)始干活了。
操作系統(tǒng)的需求演進(jìn)
那么,操作系統(tǒng)是做什么的?前面我們說(shuō)的“軟件治理”是否可以涵蓋它完整的目標(biāo)?讓我們從操作系統(tǒng)的發(fā)展歷程說(shuō)起。
最早期的計(jì)算機(jī)是大型機(jī)。這個(gè)時(shí)期的計(jì)算機(jī)笨重、昂貴,并且操作困難,主要使用人群是搞科研性質(zhì)的科學(xué)家或其他高端人群。
雖然這個(gè)時(shí)期催生了 IBM 這樣的硬件巨頭,但大多數(shù)人根本就意識(shí)不到,這玩意兒對(duì)后世人們的生活能夠產(chǎn)生如此翻天覆地的變化。
這個(gè)時(shí)期的計(jì)算機(jī)還是單任務(wù)的,以計(jì)算為主,軟件為操作硬件服務(wù)。如果我們認(rèn)為“軟件治理”是操作系統(tǒng)的根源需求的話,那么可以認(rèn)為這個(gè)時(shí)期還不存在操作系統(tǒng)。但的確會(huì)有一些輔助工具庫(kù)來(lái)簡(jiǎn)化用戶使用計(jì)算機(jī)的負(fù)擔(dān),我們可以把它看做操作系統(tǒng)的萌芽。
從這個(gè)意義來(lái)說(shuō),提供計(jì)算機(jī)的“基礎(chǔ)編程接口”,降低軟件開(kāi)發(fā)的負(fù)擔(dān),是操作系統(tǒng)更為原始的需求。
此后,小型機(jī)和個(gè)人計(jì)算機(jī)(PC)的崛起,分別誕生了 UNIX 和 DOS 這兩個(gè)影響深遠(yuǎn)的操作系統(tǒng)。UNIX 就不用說(shuō)了,它幾乎算得上今天所有現(xiàn)代操作系統(tǒng)的鼻祖。
DOS 的歷史非常有趣。首先是 IBM 沒(méi)把操作系統(tǒng)當(dāng)回事兒,把這個(gè)活兒包給了微軟。然后是微軟只花了 5 萬(wàn)美元向西雅圖公司購(gòu)買了 86-DOS 操作系統(tǒng)的版權(quán),更名為 MS-DOS。
那么 86-DOS 是怎么來(lái)的?西雅圖公司的一個(gè) 24 歲小伙叫蒂姆·帕特森(Tim Paterson),單槍匹馬花了 4 個(gè)月時(shí)間寫出來(lái)的。
可以看到,這個(gè)時(shí)期人們對(duì)操作系統(tǒng)并沒(méi)有太深刻的認(rèn)知,多數(shù)人只把它看做硬件的附屬品。IBM 不把它當(dāng)回事,西雅圖公司也沒(méi)把它當(dāng)回事,幾萬(wàn)就把它賣了。只有微軟認(rèn)認(rèn)真真地把它當(dāng)做生意做了起來(lái)(在此之前微軟的生意是賣 BASIC 語(yǔ)言的解析器起家,所以微軟一直對(duì) BASIC 語(yǔ)言情有獨(dú)鐘,直到很久以后微軟搞出了 C# 語(yǔ)言后,情況才有所改變)。
等到 IBM 意識(shí)到操作系統(tǒng)是個(gè)金蛋,改由自己做 PC-DOS 操作系統(tǒng)的時(shí)候,微軟已經(jīng)通過(guò)推動(dòng) PC 兼容機(jī)的發(fā)展,讓操作系統(tǒng)不再依賴特定的硬件設(shè)備,微軟也就因此脫離 IBM 的臂膀,自己一飛沖天了。回到問(wèn)題。要回答操作系統(tǒng)在做什么,我們可以從客戶價(jià)值和商業(yè)價(jià)值兩個(gè)維度來(lái)看。
客戶價(jià)值來(lái)說(shuō),操作系統(tǒng)首先要解決的是軟件治理的問(wèn)題,大體可分為以下六個(gè)子系統(tǒng):進(jìn)程管理、存儲(chǔ)管理、輸入設(shè)備管理、輸出設(shè)備管理、網(wǎng)絡(luò)管理、安全管理等。

操作系統(tǒng)其次解決的是基礎(chǔ)編程接口問(wèn)題。這些編程接口一方面簡(jiǎn)化了軟件開(kāi)發(fā),另一方面提供了多軟件共同運(yùn)行的環(huán)境,實(shí)現(xiàn)了軟件治理。
商業(yè)價(jià)值來(lái)說(shuō),操作系統(tǒng)是基礎(chǔ)的剛需軟件。計(jì)算機(jī)離開(kāi)了操作系統(tǒng)就是一堆廢銅爛鐵。隨著個(gè)人計(jì)算機(jī)采購(gòu)需求的急速增加,光靠軟件 License 的費(fèi)用就讓操作系統(tǒng)廠商賺翻了。
雖然第一個(gè)廣為人知的操作系統(tǒng)是 UNIX,但從商業(yè)上來(lái)說(shuō)最成功的操作系統(tǒng)則是 DOS/Windows,成就了微軟的霸主地位。
為什么是 DOS/Windows 贏得了市場(chǎng),這無(wú)關(guān)技術(shù)優(yōu)劣,關(guān)鍵在于兩者的商業(yè)路線差異:UNIX 走的是企業(yè)市場(chǎng),而 DOS/Windows 選擇了更為巨大的市場(chǎng):個(gè)人計(jì)算機(jī)(PC)市場(chǎng)。
操作系統(tǒng)也是核心的流量入口。占領(lǐng)了操作系統(tǒng),就占有了用戶,想推什么內(nèi)容給用戶都很容易。微軟對(duì)這一點(diǎn)顯然心知肚明。
這也是為什么當(dāng)年網(wǎng)景推 Netscape 瀏覽器的時(shí)候,微軟很緊張。因?yàn)闉g覽器是另一個(gè)軟件治理的入口,本質(zhì)上是操作系統(tǒng)之上的操作系統(tǒng)。如果軟件都運(yùn)行在瀏覽器上,那么本地操作系統(tǒng)就淪為和硬件一般無(wú)二的管道了。
雖然早期操作系統(tǒng)沒(méi)有應(yīng)用市場(chǎng)(AppStore),但是通過(guò)操作系統(tǒng)預(yù)裝軟件的方式向軟件廠商收租,這是一直以來(lái)都有的盈利方式。國(guó)內(nèi)盜版的番茄花園 Windows 發(fā)行版就是通過(guò)在 Windows 系統(tǒng)上預(yù)裝軟件來(lái)盈利。
當(dāng)然預(yù)裝軟件只是一種可能性,流量變現(xiàn)的方式還有很多。蘋果的 iOS 操作系統(tǒng)開(kāi)啟了新的玩法,它構(gòu)建了新的商業(yè)閉環(huán):賬號(hào)(Account)、支付(Pay)、應(yīng)用市場(chǎng)(AppStore)。
我們把這個(gè)商業(yè)模式叫收稅模式。帳號(hào)(注意是互聯(lián)網(wǎng)賬號(hào),不是過(guò)去用于權(quán)限管理的本地賬號(hào))是前提。沒(méi)有帳號(hào),就沒(méi)有支付系統(tǒng),也沒(méi)有辦法判斷用戶是否購(gòu)買過(guò)某個(gè)軟件。
應(yīng)用市場(chǎng)實(shí)現(xiàn)了應(yīng)用的分發(fā),既解決了系統(tǒng)能力的無(wú)限擴(kuò)展問(wèn)題(客戶價(jià)值),也解決了預(yù)裝軟件的軟件個(gè)數(shù)總歸有限的問(wèn)題(商業(yè)價(jià)值)。支付則是收稅模式的承載體,無(wú)論是下載應(yīng)用收費(fèi),還是應(yīng)用內(nèi)購(gòu)買內(nèi)容收費(fèi),都可以通過(guò)這個(gè)關(guān)卡去收稅。
無(wú)論是本地操作系統(tǒng) iOS 和 Android,還是 Web 操作系統(tǒng)(瀏覽器)如微信小程序,都實(shí)現(xiàn)了“帳號(hào) - 支付 - 應(yīng)用市場(chǎng)”這樣的商業(yè)閉環(huán)。這類操作系統(tǒng),我們不妨把它叫做現(xiàn)代操作系統(tǒng)。
操作系統(tǒng)的邊界在哪里?
架構(gòu)的第一步是需求分析。上一節(jié)我提到了在架構(gòu)設(shè)計(jì)過(guò)程中,需求分析至少應(yīng)該花費(fèi)三分之一的精力。通過(guò)這一節(jié)我們對(duì)操作系統(tǒng)演進(jìn)過(guò)程的回顧,你可能更容易體會(huì)到這一點(diǎn)。
當(dāng)我們說(shuō)要做一個(gè)操作系統(tǒng)的時(shí)候,實(shí)際上我們自己對(duì)這句話的理解也是非常模糊的。尤其是我們正準(zhǔn)備去做的事情是一個(gè)新生事物時(shí),我們對(duì)其理解往往更加粗淺。
在本專欄開(kāi)篇詞中我也提過(guò),架構(gòu)也關(guān)乎用戶需求,作為架構(gòu)師我們不只是要知道當(dāng)前的用戶需求是什么,我們還要預(yù)測(cè)需求未來(lái)可能的變化,預(yù)判什么會(huì)發(fā)生,而什么一定不會(huì)發(fā)生。
我們可以問(wèn)一下自己:我是否能夠預(yù)料到,有一天支付(Pay)系統(tǒng)會(huì)成為操作系統(tǒng)的核心子系統(tǒng)?如果不能,那么怎么才能做到?
操作系統(tǒng)的邊界到底在哪里?要回答這個(gè)問(wèn)題,我們需要看清楚硬件、操作系統(tǒng)和瀏覽器三個(gè)角色的關(guān)系:
首先我們來(lái)看操作系統(tǒng)與硬件的關(guān)系。如果操作系統(tǒng)廠商不做硬件會(huì)怎樣?我們知道個(gè)人計(jì)算機(jī)(PC)市場(chǎng)就是如此。微軟雖然占據(jù)了 PC 操作系統(tǒng)(DOS/Windows)絕大部分江山,但是它自身并不生產(chǎn)硬件。這里面,PC 兼容機(jī)的發(fā)展對(duì) DOS/Windows 的發(fā)展有著至關(guān)重要的支撐意義。它讓操作系統(tǒng)廠商有了獨(dú)立的生存空間。
到了移動(dòng)時(shí)代,Google 收購(gòu) Android 后,通過(guò)免費(fèi)策略占領(lǐng)移動(dòng)操作系統(tǒng)的大半江山,一定程度上復(fù)制了微軟的過(guò)程,但實(shí)際上并沒(méi)有那么理想。
首先,Android 是免費(fèi)的,Google 并沒(méi)有從中收取軟件 License 費(fèi)用,而是借助 Android 的市場(chǎng)占有率來(lái)推動(dòng) Google 的服務(wù)(例如搜索、Gmail 等等),通過(guò) Google 服務(wù)來(lái)獲取商業(yè)回報(bào)。
其次,iOS 操作系統(tǒng)引入的 “賬號(hào) - 支付 - 應(yīng)用市場(chǎng)” 的收稅模式,受益方是硬件(手機(jī))廠商,而非操作系統(tǒng)廠商。其中最關(guān)鍵的一點(diǎn),幾乎所有手機(jī)廠商都不接受把支付(Pay)這個(gè)核心系統(tǒng)交給 Google。
最后,不止支付系統(tǒng),一旦手機(jī)廠商長(zhǎng)大立足 ,Google 服務(wù)也會(huì)被逐步替換。所以 Google 和 Android 手機(jī)廠商之間的聯(lián)盟并不可靠,養(yǎng)肥的手機(jī)廠商會(huì)不斷試探 Google 的底線,而 Google 也會(huì)嘗試去收緊政策,雙方在博弈中達(dá)到平衡。
之所以會(huì)這樣,我覺(jué)得原因有這么幾個(gè):
其一,歷史是不可復(fù)制的,人們對(duì)操作系統(tǒng)的重要性認(rèn)知已經(jīng)非常充分。所以大部分手機(jī)廠商,都不會(huì)放棄操作系統(tǒng)的核心子系統(tǒng)的主控權(quán)。Android 系統(tǒng)的開(kāi)源策略無(wú)法完全達(dá)到預(yù)期的目標(biāo),這也是 Google 最終還是免不了要自己做手機(jī)的原因。
其二,手機(jī)是個(gè)性化產(chǎn)品,硬件上并沒(méi)有 PC 那么標(biāo)準(zhǔn)化。所以個(gè)人計(jì)算機(jī)有兼容機(jī),而手機(jī)并沒(méi)有所謂的標(biāo)準(zhǔn)化硬件。
分析完操作系統(tǒng)和硬件的關(guān)系,我們?cè)賮?lái)看它和瀏覽器的關(guān)系。在 PC 時(shí)期,操作系統(tǒng)和瀏覽器看起來(lái)至少需求上是有差異化的:操作系統(tǒng),是以管理本地軟件和內(nèi)容為主(對(duì)內(nèi))。瀏覽器,是以管理互聯(lián)網(wǎng)內(nèi)容為主(對(duì)外)。但,這個(gè)邊界必然會(huì)越來(lái)越模糊。
從商業(yè)價(jià)值來(lái)說(shuō),操作系統(tǒng)是剛性需求,核心的流量入口,兵家必爭(zhēng)之地。所以,圍繞它的核心能力,操作系統(tǒng)必然會(huì)不斷演化出新的形態(tài)。
操作系統(tǒng)的邊界到底在什么地方?我們通過(guò)分析硬件、操作系統(tǒng)、瀏覽器三者的關(guān)系,也做了定性的分析。這樣的分析將有助于你對(duì)需求發(fā)展做出預(yù)判。
操作系統(tǒng)的核心職能是軟件治理,而軟件治理的一個(gè)很重要的部分,就是讓多個(gè)軟件可以共同合理使用計(jì)算機(jī)的資源,不至于出現(xiàn)爭(zhēng)搶的局面。內(nèi)存作為計(jì)算機(jī)最基礎(chǔ)的硬件資源,有著非常特殊的位置。我們知道,CPU 可以直接訪問(wèn)的存儲(chǔ)資源非常少,只有:寄存器、內(nèi)存(RAM)、主板上的 ROM。寄存器的訪問(wèn)速度非常非常快,但是數(shù)量很少,大部分程序員不直接打交道,而是由編程語(yǔ)言的編譯器根據(jù)需要自動(dòng)選擇寄存器來(lái)優(yōu)化程序的運(yùn)行性能。
主板上的 ROM 是非易失的只讀的存儲(chǔ)。所謂非易失,是計(jì)算機(jī)重新啟動(dòng)后它里面的數(shù)據(jù)仍然會(huì)存在。這不像內(nèi)存(RAM),計(jì)算機(jī)重新啟動(dòng)后它上面的數(shù)據(jù)就丟失了。ROM 非易失和只讀的特點(diǎn),決定了它非常適合存儲(chǔ)計(jì)算機(jī)的啟動(dòng)程序(BIOS)。所以你可以看到,內(nèi)存的地位非常特殊,它是唯一的 CPU 內(nèi)置支持,且和程序員直接會(huì)打交道的基礎(chǔ)資源。

從圖中可以看出,存儲(chǔ)的作用有兩個(gè):一個(gè)是作為 “計(jì)算” 的操作對(duì)象,輸入和輸出數(shù)據(jù)存放的所在;另一個(gè)是存放 “計(jì)算” 本身,也就是程序員寫的程序。這里說(shuō)的存儲(chǔ),主要指的就是內(nèi)存。
當(dāng)然,這是從 CPU 角度看到的視圖:對(duì)于 CPU 來(lái)說(shuō),“計(jì)算” 過(guò)程從計(jì)算機(jī)加電啟動(dòng),執(zhí)行 BIOS 程序的第一條指令開(kāi)始,到最后計(jì)算機(jī)關(guān)機(jī),整個(gè)就是一個(gè)完整的 “計(jì)算” 過(guò)程。這個(gè)過(guò)程有多少個(gè)“子的 ‘計(jì)算’過(guò)程”,它并不關(guān)心。但是從操作系統(tǒng)的視角來(lái)看,計(jì)算機(jī)從開(kāi)機(jī)到關(guān)機(jī),整個(gè) “計(jì)算” 過(guò)程,由很多軟件,也就是子 “計(jì)算” 過(guò)程,共同完成。從時(shí)序來(lái)說(shuō),計(jì)算機(jī)完整的 “計(jì)算” 過(guò)程如下:

整個(gè) “計(jì)算” 過(guò)程的每個(gè)子過(guò)程都有其明確的考量。?
首先,BIOS 程序沒(méi)有固化在 CPU 中,而是獨(dú)立放到主板的 ROM 上,是因?yàn)椴煌瑲v史時(shí)期的計(jì)算機(jī)輸入輸出設(shè)備很不一樣,有鍵盤 + 鼠標(biāo) + 顯示器的,有觸摸屏的,也有純語(yǔ)音交互的,外置存儲(chǔ)則有軟盤,硬盤,閃存,這些變化我們通過(guò)調(diào)整 BIOS 程序就可以應(yīng)對(duì),而不需要修改 CPU。
引導(dǎo)區(qū)引導(dǎo)程序,則是程序從內(nèi)置存儲(chǔ)(ROM)轉(zhuǎn)到外置存儲(chǔ)的邊界。引導(dǎo)區(qū)引導(dǎo)程序很短,BIOS 只需要把它加載到內(nèi)存執(zhí)行就可以,但是這樣系統(tǒng)的控制權(quán)就很巧妙地轉(zhuǎn)到外置存儲(chǔ)了。?
引導(dǎo)區(qū)引導(dǎo)程序不固化在 BIOS 中,而是寫在外置存儲(chǔ)的引導(dǎo)區(qū),是為了避免 BIOS 程序需要經(jīng)常性修改。畢竟 BIOS 還是硬件,而引導(dǎo)區(qū)引導(dǎo)程序已經(jīng)屬于軟件范疇了,修改起來(lái)會(huì)方便很多。
OS 引導(dǎo)程序,則是外置存儲(chǔ)接手計(jì)算機(jī)控制權(quán)的真正開(kāi)始。這里 OS 是操作系統(tǒng)(Operating System)的縮寫。操作系統(tǒng)從這里開(kāi)始干活了。這個(gè)過(guò)程發(fā)生了很多很多事情,這里我們先略過(guò)。但是最終所有的初始化工作完成后,操作系統(tǒng)會(huì)把執(zhí)行權(quán)交給 OSShell 程序。?
OS Shell 程序負(fù)責(zé)操作系統(tǒng)與用戶的交互。最早的時(shí)候,計(jì)算機(jī)的交互界面是字符界面,OS Shell 程序是一個(gè)命令行程序。DOS 中叫 command.com,而在 Linux 下則叫 sh 或者bash 之類。這里的 sh 就是 shell 的縮寫。
這個(gè)時(shí)期啟動(dòng)一個(gè)軟件的方式就是在 Shell 程序中輸入一個(gè)命令行,Shell 負(fù)責(zé)解釋命令行理解用戶的意圖,然后啟動(dòng)相應(yīng)的軟件。到了圖形界面時(shí)期,在 Shell 中啟動(dòng)軟件就變成點(diǎn)點(diǎn)鼠標(biāo),或者動(dòng)動(dòng)手指(觸摸屏)就行了,交互范式簡(jiǎn)化了很多。?
在了解了計(jì)算機(jī)從開(kāi)機(jī)到關(guān)機(jī)的整個(gè)過(guò)程后,你可能很快會(huì)發(fā)現(xiàn),這里面有一個(gè)很關(guān)鍵的細(xì)節(jié)沒(méi)有交代:計(jì)算機(jī)是如何運(yùn)行外置存儲(chǔ)上的軟件的?
這和內(nèi)存管理有關(guān)。結(jié)合內(nèi)存的作用,我們談內(nèi)存管理,只需要談清楚兩個(gè)問(wèn)題:?如何分配內(nèi)存(給運(yùn)行中的軟件,避免它們發(fā)生資源爭(zhēng)搶);?如何運(yùn)行外置存儲(chǔ)(比如硬盤)上的軟件?
在回答這兩個(gè)問(wèn)題之前,我們先了解一個(gè)背景知識(shí):CPU 的實(shí)模式和保護(hù)模式。這兩個(gè)模式 CPU 對(duì)內(nèi)存的操作方式完全不同。在實(shí)模式下,CPU 直接通過(guò)物理地址訪問(wèn)內(nèi)存。在保護(hù)模式下,CPU 通過(guò)一個(gè)地址映射表把虛擬的內(nèi)存地址轉(zhuǎn)為物理的內(nèi)存地址,然后再去讀取數(shù)據(jù)。相應(yīng)的,工作在實(shí)模式下的操作系統(tǒng),我們叫實(shí)模式操作系統(tǒng);工作在保護(hù)模式下的操作系統(tǒng),我們叫保護(hù)模式操作系統(tǒng)。?
先看實(shí)模式操作系統(tǒng)。在實(shí)模式操作系統(tǒng)下,所有軟件包括操作系統(tǒng)本身,都在同一個(gè)物理地址空間下。在 CPU看來(lái),它們是同一個(gè)程序。操作系統(tǒng)如何分配內(nèi)存?至少有兩種可行的方法。?
其一,把操作系統(tǒng)內(nèi)存管理相關(guān)的函數(shù)地址,放到一個(gè)大家公認(rèn)的地方(比如 0x10000處),每個(gè)軟件要想申請(qǐng)內(nèi)存就到這個(gè)地方取得內(nèi)存管理函數(shù)并調(diào)用它。?
其二,把內(nèi)存管理功能設(shè)計(jì)為一個(gè)中斷請(qǐng)求。所謂中斷,是 CPU 響應(yīng)硬件設(shè)備事件的一個(gè)機(jī)制。當(dāng)某個(gè)輸入輸出設(shè)備發(fā)生了一件需要 CPU 來(lái)處理的事情,它就會(huì)觸發(fā)一個(gè)中斷。?
但實(shí)模式有兩個(gè)問(wèn)題。其一是安全性。操作系統(tǒng)以及所有軟件都運(yùn)行在一起,相互之間可以隨意修改對(duì)方的數(shù)據(jù)甚至程序指令,這樣搞破壞就非常容易。其二是支持的軟件復(fù)雜性低,同時(shí)可運(yùn)行的軟件數(shù)量少。
一方面,軟件越復(fù)雜,它的程序代碼量就越多,需要的存儲(chǔ)空間越大,甚至可能出現(xiàn)單個(gè)軟件的大小超過(guò)計(jì)算機(jī)的可用內(nèi)存,這時(shí)在實(shí)模式下就沒(méi)法執(zhí)行它。另一方面,哪怕單個(gè)軟件可運(yùn)行,但是一旦我們同時(shí)運(yùn)行的軟件多幾個(gè),操作系統(tǒng)對(duì)內(nèi)存的需求量就會(huì)急劇增加。相比這么多軟件加起來(lái)的內(nèi)存需求量,內(nèi)存的存儲(chǔ)空間往往仍然是不足的。
但是為什么平常我們可以毫無(wú)顧忌地不斷打開(kāi)新的軟件,從來(lái)不曾擔(dān)心過(guò)內(nèi)存會(huì)不足呢?這就是保護(hù)模式的作用了。保護(hù)模式下,內(nèi)存訪問(wèn)不再是直接通過(guò)物理內(nèi)存,而是基于虛擬內(nèi)存。虛擬內(nèi)存模式下,整個(gè)內(nèi)存空間被分成很多個(gè)連續(xù)的內(nèi)存頁(yè)。每個(gè)內(nèi)存頁(yè)大小是固定的,比如 64K。這樣,每次 CPU 訪問(wèn)某個(gè)虛擬內(nèi)存地址中的數(shù)據(jù),它都會(huì)先計(jì)算出這是要訪問(wèn)哪個(gè)內(nèi)存頁(yè),然后 CPU 再通過(guò)一個(gè)地址映射表,把虛擬的內(nèi)存地址轉(zhuǎn)為物理的內(nèi)存地址,然后到這個(gè)物理內(nèi)存地址去讀取數(shù)據(jù)。地址映射表是一個(gè)數(shù)組,下標(biāo)是內(nèi)存頁(yè)頁(yè)號(hào),值是該內(nèi)存頁(yè)對(duì)應(yīng)的物理內(nèi)存首地址。
當(dāng)然,也有可能某一個(gè)內(nèi)存頁(yè)對(duì)應(yīng)的物理內(nèi)存地址還不存在,這種情況叫缺頁(yè),沒(méi)法讀取數(shù)據(jù),這時(shí) CPU 就會(huì)發(fā)起一個(gè)缺頁(yè)的中斷請(qǐng)求。

這個(gè)缺頁(yè)的中斷請(qǐng)求會(huì)被操作系統(tǒng)接管。發(fā)生缺頁(yè)時(shí),操作系統(tǒng)會(huì)為這個(gè)內(nèi)存頁(yè)分配物理的內(nèi)存,并恢復(fù)這個(gè)內(nèi)存頁(yè)的數(shù)據(jù)。如果沒(méi)有空閑的物理內(nèi)存可以分配,它就會(huì)選擇一個(gè)最久沒(méi)有被訪問(wèn)的內(nèi)存頁(yè)進(jìn)行淘汰。
當(dāng)然,淘汰前會(huì)把這個(gè)內(nèi)存頁(yè)的數(shù)據(jù)保存起來(lái),因?yàn)橄麓?CPU 訪問(wèn)這個(gè)被淘汰的內(nèi)存頁(yè)時(shí)一樣會(huì)發(fā)生缺頁(yè)中斷請(qǐng)求,那時(shí)操作系統(tǒng)還要去恢復(fù)數(shù)據(jù)。通過(guò)這個(gè)虛擬內(nèi)存的機(jī)制,操作系統(tǒng)并不需要一上來(lái)就把整個(gè)軟件裝進(jìn)內(nèi)存中,而是通過(guò)缺頁(yè)中斷按需加載對(duì)應(yīng)的程序代碼片段。多個(gè)軟件同時(shí)運(yùn)行的問(wèn)題也解決了,內(nèi)存不夠用的時(shí)候,就把最久沒(méi)有用過(guò)的內(nèi)存頁(yè)淘汰掉,騰出物理內(nèi)存出來(lái)。
運(yùn)行軟件的問(wèn)題解決了。那么,操作系統(tǒng)如何分配內(nèi)存給運(yùn)行中的軟件?其實(shí),內(nèi)存分配的問(wèn)題也解決了,并不需要任何額外的機(jī)制。反正內(nèi)存地址空間是虛擬的,操作系統(tǒng)可以一上來(lái)就給要運(yùn)行的軟件分配超級(jí)大的內(nèi)存,你想怎么用隨你。軟件如果不用某個(gè)內(nèi)存頁(yè),什么都不發(fā)生。軟件一旦用了某個(gè)內(nèi)存頁(yè),通過(guò)缺頁(yè)中斷,操作系統(tǒng)就分配真正的物理內(nèi)存給它。
通過(guò)引入虛擬內(nèi)存及其缺頁(yè)機(jī)制,CPU 很好地解決了操作系統(tǒng)和軟件的配合關(guān)系。每個(gè)運(yùn)行中的軟件,我們把它叫進(jìn)程,都有自己的地址映射表。也就是說(shuō),虛擬地址并不是全局的,而是每個(gè)進(jìn)程有一個(gè)自己獨(dú)立的虛擬地址空間。
在保護(hù)模式下,計(jì)算機(jī)的基礎(chǔ)架構(gòu)體系和操作系統(tǒng)共同在努力做的一件事情,就是讓每個(gè)軟件“感覺(jué)”自己在獨(dú)占整個(gè)計(jì)算機(jī)的資源。獨(dú)立的虛擬地址空間很好地偽裝了這一點(diǎn):看起來(lái)我獨(dú)自在享用所有內(nèi)存資源。在實(shí)模式下的浮動(dòng)地址的問(wèn)題也解決了,軟件可以假設(shè)自己代碼加載的絕對(duì)地址是什么,不需要在加載的時(shí)候重新調(diào)整 CPU 指令操作的地址。
這和實(shí)模式很不一樣。在實(shí)模式下,所有進(jìn)程都在同在物理內(nèi)存的地址空間里,它們相互可以訪問(wèn)對(duì)方的數(shù)據(jù),修改甚至破壞對(duì)方的數(shù)據(jù),進(jìn)而導(dǎo)致其他進(jìn)程(包括操作系統(tǒng)本身的進(jìn)程)崩潰。內(nèi)存是進(jìn)程運(yùn)行的基礎(chǔ)資源,保持進(jìn)程基礎(chǔ)資源的獨(dú)立性,是軟件治理的最基礎(chǔ)的要求。這也是保護(hù)模式之所以叫“保護(hù)”模式的原因。
虛擬內(nèi)存它本質(zhì)上要解決這樣兩個(gè)很核心的需求。其一,軟件越來(lái)越大,我們需要考慮在外置存儲(chǔ)上執(zhí)行指令,而不是完整加載到內(nèi)存中。但是外置存儲(chǔ)一方面它的數(shù)據(jù) CPU 并不知道怎么讀;另一方面就算知道怎么讀,也不知道它的數(shù)據(jù)格式是什么樣的,這依賴文件系統(tǒng)的設(shè)計(jì)。讓 CPU 理解外置存儲(chǔ)的實(shí)現(xiàn)細(xì)節(jié)?這并不是一個(gè)好的設(shè)計(jì)。?
其二,要同時(shí)運(yùn)行的軟件越來(lái)越多,計(jì)算機(jī)內(nèi)存的供給與軟件運(yùn)行的內(nèi)存需求相比,捉襟見(jiàn)肘。怎么才能把有限的內(nèi)存的使用效率最大化?一個(gè)很容易想到的思路是把不經(jīng)常使用的內(nèi)存數(shù)據(jù)交換到外置存儲(chǔ)。但是問(wèn)題仍然是,CPU 并不了解外置存儲(chǔ)的實(shí)現(xiàn)細(xì)節(jié),怎么才能把內(nèi)存按需交換出去??
通過(guò)把虛擬內(nèi)存地址分頁(yè),引入缺頁(yè)中斷,我們非常巧妙地解決了這個(gè)問(wèn)題。缺頁(yè)中斷很像是 CPU 留給操作系統(tǒng)的回調(diào)函數(shù),通過(guò)它對(duì)變化點(diǎn)實(shí)現(xiàn)了很好的開(kāi)放性設(shè)計(jì)。
總結(jié)一下。我們今天先概要地闡述了計(jì)算機(jī)運(yùn)行的全過(guò)程,并對(duì)每一步的核心意義做了簡(jiǎn)單的介紹。然后我們把話題轉(zhuǎn)到我們這一節(jié)的重心:內(nèi)存管理。談內(nèi)存管理,需要談清楚兩個(gè)核心問(wèn)題:
如何分配內(nèi)存(給運(yùn)行中的軟件,避免它們發(fā)生資源爭(zhēng)搶);如何運(yùn)行外置存儲(chǔ)(比如硬盤)上的軟件。我們分別就在實(shí)模式下和保護(hù)模式下的內(nèi)存管理進(jìn)行了討論。
架構(gòu)師專欄:

轉(zhuǎn)載申明:轉(zhuǎn)載本號(hào)文章請(qǐng)注明作者和來(lái)源,本號(hào)發(fā)布文章若存在版權(quán)等問(wèn)題,請(qǐng)留言聯(lián)系處理,謝謝。
推薦閱讀
更多架構(gòu)相關(guān)技術(shù)知識(shí)總結(jié)請(qǐng)參考“架構(gòu)師全店鋪技術(shù)資料打包”相關(guān)電子書(37本技術(shù)資料打包匯總詳情可通過(guò)“閱讀原文”獲取)。
全店內(nèi)容持續(xù)更新,現(xiàn)下單“全店鋪技術(shù)資料打包(全)”,后續(xù)可享全店內(nèi)容更新“免費(fèi)”贈(zèng)閱,價(jià)格僅收198元(原總價(jià)350元)。
溫馨提示:
掃描二維碼關(guān)注公眾號(hào),點(diǎn)擊閱讀原文鏈接獲取“架構(gòu)師技術(shù)全店資料打包匯總(全)”電子書資料詳情。

