1、概要
1.1昔园、信息就是位+上下文
計(jì)算機(jī)系統(tǒng)是由硬件和系統(tǒng)軟件組成的僻弹,它們共同工作來運(yùn)行應(yīng)用程序阿浓。所有計(jì)算機(jī)系統(tǒng)都有相似的硬件和軟件組件,它們執(zhí)行著相似的功能奢方。
從某種意義上來說搔扁,本書的目的就是要幫助你了解當(dāng)你在系統(tǒng)上執(zhí)行 hello 程序時(shí),系統(tǒng)發(fā)生了什么以及為什么會(huì)這樣蟋字。
// hello 程序
#include <stdio.h>
int main()
{
printf("hello, world\n");
}
hello 程序的生命周期是從一個(gè)源程序(或者說源文件)開始的,即程序員利用編輯器創(chuàng)建并保存的文本文件扭勉,文件名是 hello.c鹊奖。源程序?qū)嶋H上就是一個(gè)由值 0 和 1 組成的位(bit)序列,8 個(gè)位被組織成一組涂炎,稱為字節(jié)忠聚。每個(gè)字節(jié)表示程序中某個(gè)文本字符。
hello 源程序是文本編輯器編寫的一個(gè)文件唱捣,使用 HxD (免費(fèi)的十六進(jìn)制和磁盤數(shù)據(jù)編輯器)對(duì)源文件進(jìn)行源碼查看:
從上圖可以看見两蟀,所有的源碼字符最終都會(huì)被轉(zhuǎn)為對(duì)應(yīng)的數(shù)字。像 hello.c 這樣只由 ASCII 字符構(gòu)成的文件稱為文本文件震缭,所有其他文件都稱為二進(jìn)制文件赂毯。hello.c 的表示方法說明了一個(gè)基本的思想 :系統(tǒng)中所有的信息(包括磁盤文件、存儲(chǔ)器中的程序、存儲(chǔ)器中存放的用戶數(shù)據(jù)以及網(wǎng)絡(luò)上傳送的數(shù)據(jù))党涕,都是由一串位表示的烦感。區(qū)分不同數(shù)據(jù)對(duì)象的唯一方法是我們讀到這些數(shù)據(jù)對(duì)象時(shí)的上下文。比如膛堤,在不同的上下文中手趣,一個(gè)同樣的字節(jié)序列可能表示一個(gè)整數(shù)、浮點(diǎn)數(shù)肥荔、字符串或者機(jī)器指令绿渣。
1.2、編譯系統(tǒng)如何工作
? hello.c 是肉眼可直接識(shí)別的文本文件燕耿,但作為機(jī)器來說中符,它只認(rèn)識(shí)二進(jìn)制數(shù)字(物理邏輯上對(duì)應(yīng)的是:不同大小電流或高低的電壓),文件均附生在操作系統(tǒng)之上缸棵,我們需要一套完整的流程將源文件翻譯成機(jī)器可以直接看懂并執(zhí)行的可執(zhí)行文件舟茶,執(zhí)行這四個(gè)階段的程序(預(yù)處理器、編譯器堵第、匯編器和鏈接器)一起構(gòu)成了編譯系統(tǒng)(compilation system)吧凉。
- 預(yù)處理階段: 預(yù)處理器(cpp)根據(jù)以字符 # 開頭的命令,修改原始的 C 程序踏志。比如 hello.c 中第 1 行的 #include 命令告訴預(yù)處理器讀取系統(tǒng)頭文件 stdio.h 的內(nèi)容阀捅,并把它直接插入到程序文本中。結(jié)果就得到了另一個(gè) C 程序针余,通常是以 .i 作為文件擴(kuò)展名饲鄙。
- 編譯階段: 編譯器(cc1)將文本文件 hello.i 翻譯成文本文件 hello.s,它包含一個(gè)匯編語言程序圆雁。匯編語言程序中的每條語句都以一種標(biāo)準(zhǔn)的文本格式確切地描述了一條低級(jí)機(jī)器語言指令忍级。匯編語言是非常有用的,因?yàn)樗鼮椴煌呒?jí)語言的不同編譯器提供了通用的輸出語言伪朽。例如轴咱,C 編譯器和 Fortran 編譯器產(chǎn)生的輸出文件用的都是一樣的匯編語言。
- 匯編階段: 接下來烈涮,匯編器(as)將 hello.s 翻譯成機(jī)器語言指令朴肺,把這些指令打包成一種叫做可重定位目標(biāo)程序(relocatable object program)的格式,并將結(jié)果保存在目標(biāo)文件 hello.o 中坚洽。hello.o 文件是一個(gè)二進(jìn)制文件戈稿,它的字節(jié)編碼是機(jī)器語言指令而不是字符。如果我們?cè)谖谋揪庉嬈髦写蜷_ hello.o 文件讶舰,看到的將是一堆亂碼鞍盗。
- 鏈接階段: 請(qǐng)注意需了,hello 程序調(diào)用了 printf 函數(shù),它是每個(gè) C 編譯器都會(huì)提供的標(biāo)準(zhǔn) C 庫(kù)中的一個(gè)函數(shù)橡疼。printf 函數(shù)存在于一個(gè)名為 printf.o 的單獨(dú)的預(yù)編譯好了的目標(biāo)文件中援所,而這個(gè)文件必須以某種方式合并到我們的 hello.o 程序中。鏈接器(ld)就負(fù)責(zé)處理這種合并欣除。結(jié)果就得到 hello 文件住拭,它是一個(gè)可執(zhí)行目標(biāo)文件(或者簡(jiǎn)稱為可執(zhí)行文件),可以被加載到內(nèi)存中历帚,由系統(tǒng)執(zhí)行滔岳。
1.3、高速緩存
隨機(jī)訪問存儲(chǔ)器( Random-Access Memory,RAM)分為兩類:靜態(tài)的和動(dòng)態(tài)的挽牢。靜態(tài)RAM(SRAM)比動(dòng)態(tài)RAM(DRAM)更快谱煤,但也貴得多。SRAM用來作為高速緩存存儲(chǔ)器禽拔。DRAM用來作為主存以及圖形系統(tǒng)的幀緩沖區(qū)刘离。
靜態(tài)RAM
SRAM將每個(gè)位存儲(chǔ)在一個(gè)雙穩(wěn)態(tài)的( bistable)存儲(chǔ)器單元里。每個(gè)單元是用一個(gè)六晶體管電路來實(shí)現(xiàn)的睹栖。這個(gè)電路有這樣一個(gè)屬性硫惕,它可以無限期地保持在兩個(gè)不同的電壓配置( configuration)或狀態(tài)( state)之一。其他任何狀態(tài)都是不穩(wěn)定的野来,在不穩(wěn)定狀態(tài)時(shí)恼除,電路會(huì)迅速轉(zhuǎn)移到兩個(gè)穩(wěn)定狀態(tài)的一個(gè)。
由于SRAM存儲(chǔ)器單元的雙穩(wěn)態(tài)特性曼氛,只要有電豁辉,它就會(huì)永遠(yuǎn)地保持它的值。即使有干擾(例如電子噪音)來擾亂電壓舀患,當(dāng)干擾消除時(shí)徽级,電路就會(huì)恢復(fù)到穩(wěn)定值。
動(dòng)態(tài)RAM
DRAM將每個(gè)位存儲(chǔ)為對(duì)一個(gè)電容的充電聊浅。DRAM存儲(chǔ)器可以制造得非常密集灰追。每個(gè)單元由一個(gè)電容和一個(gè)訪問晶體管組成。但是狗超,與SRAM不同,DRAM存儲(chǔ)器單元對(duì)干擾非常敏感朴下。當(dāng)電容的電壓被擾亂之后努咐,它就永遠(yuǎn)不會(huì)恢復(fù)了。暴露在光線下會(huì)導(dǎo)致電容電壓改變殴胧。
高速緩存存儲(chǔ)器
高速緩存關(guān)于讀的操作非常簡(jiǎn)單渗稍。首先佩迟,在高速緩存中查找所需字ww的副本。如果命中竿屹,立即返回字ww給CPU报强。如果不命中,從存儲(chǔ)器層次結(jié)構(gòu)中較低層中取出包含字ww的塊拱燃,將這個(gè)塊存儲(chǔ)到某個(gè)高速緩存行中(可能會(huì)驅(qū)逐一個(gè)有效的行)秉溉,然后返回字ww。
寫的情況就要復(fù)雜一些了碗誉。假設(shè)我們要寫一個(gè)已經(jīng)緩存了的字ww(寫命中召嘶, write hit)。在高速緩存更新了它的ww的副本之后哮缺,怎么更新ww在層次結(jié)構(gòu)中緊接著低一層中的副本呢弄跌?最簡(jiǎn)單的方法,稱為直寫( write-through)尝苇,就是立即將ww的高速緩存塊寫回到緊接著的低一層中铛只。雖然簡(jiǎn)單,但是直寫的缺點(diǎn)是每次寫都會(huì)引起總線流量糠溜。另一種方法淳玩,稱為寫回( write-back),盡可能地推遲更新诵冒,只有當(dāng)替換算法要驅(qū)逐這個(gè)更新過的塊時(shí)凯肋,才把它寫到緊接著的低一層中。由于局部性汽馋,寫回能顯著地減少總線流量侮东,但是它的缺點(diǎn)是增加了復(fù)雜性。高速緩存必須為每個(gè)高速緩存行維護(hù)一個(gè)額外的修改位( dirty bit)豹芯,表明這個(gè)高速緩存塊是否被修改過悄雅。
另一個(gè)問題是如何處理寫不命中。一種方法铁蹈,稱為寫分配( write-allocate)宽闲,加載相應(yīng)的低一層中的塊到高速緩存中,然后更新這個(gè)高速緩存塊握牧。寫分配試圖利用寫的空間局部性容诬,但是缺點(diǎn)是每次不命中都會(huì)導(dǎo)致一個(gè)塊從低一層傳送到高速緩存。另一種方法沿腰,稱為非寫分配(not- write-allocate)览徒,避開高速緩存,直接把這個(gè)字寫到低一層中颂龙。直寫高速緩存通常是非寫分配的习蓬。寫回高速緩存通常是寫分配的纽什。
高速緩存既保存數(shù)據(jù),也保存指令躲叼。只保存指令的高速緩存稱為 i-cache芦缰。只保存程序數(shù)據(jù)的高速緩存稱為 d-cache。既保存指令又包括數(shù)據(jù)的高速緩存稱為統(tǒng)一的高速緩存( unified cache)》憧叮現(xiàn)代處理器包括獨(dú)立的 i-cache和d-cache让蕾。這樣做有很多原因。有兩個(gè)獨(dú)立的高速緩存流礁,處理器能夠同時(shí)讀一個(gè)指令字和一個(gè)數(shù)據(jù)字涕俗。 i-cache通常是只讀的劝枣,因此比較簡(jiǎn)單碟狞。通常會(huì)針對(duì)不同的訪問模式來優(yōu)化這兩個(gè)高速緩存,它們可以有不同的塊大小编整,相聯(lián)度和容量找御。使用不同的高速緩存也確保了數(shù)據(jù)訪問不會(huì)與指令訪問形成沖突不命中元镀,反過來也是一樣,代價(jià)就是可能會(huì)引起容量不命中增加霎桅。
1.4栖疑、存儲(chǔ)設(shè)備層次結(jié)構(gòu)
存儲(chǔ)技術(shù)和計(jì)算機(jī)軟件的一些基本的和持久的屬性:
??存儲(chǔ)技術(shù):不同存儲(chǔ)技術(shù)的訪問時(shí)間差異很大。速度較快的技術(shù)每字節(jié)的成本要比速度較慢的技術(shù)高滔驶,而且容量較小遇革。CPU和主存之間的速度差距在增大。
??計(jì)算機(jī)軟件:一個(gè)編寫良好的程序傾向于展示出良好的局部性揭糕。
硬件和軟件的這些基本屬性互相補(bǔ)充得很完美萝快。它們這種相互補(bǔ)充的性質(zhì)使人想到一種組織存儲(chǔ)器系統(tǒng)的方法,稱為存儲(chǔ)器層次結(jié)構(gòu)( memory hierarchy)著角,下圖展示了一個(gè)典型的存儲(chǔ)器層次結(jié)構(gòu)揪漩。一般而言,從高層往底層走吏口,存儲(chǔ)設(shè)備變得更慢奄容、更便宜和更大。在最高層(L0)产徊,是少量快速的CPU寄存器昂勒,CPU可以在一個(gè)時(shí)鐘周期內(nèi)訪問它們。接下來是一個(gè)或多個(gè)小型到中型的基于SRAM的高速緩存存儲(chǔ)器舟铜,可以在幾個(gè)CPU時(shí)鐘周期內(nèi)訪問它們叁怪。然后是一個(gè)大的基于DRAM的主存,可以在幾十到幾百個(gè)時(shí)鐘周期內(nèi)訪問它們深滚。接下來是慢速但是容量很大的本地磁盤奕谭。最后,有些系統(tǒng)甚至包括了一層附加的遠(yuǎn)程服務(wù)器上的磁盤痴荐,要通過網(wǎng)絡(luò)來訪問它們血柳。
存儲(chǔ)器結(jié)構(gòu)中的緩存
一般而言,高速緩存( cache生兆,讀作“cash”)是一個(gè)小而快速的存儲(chǔ)設(shè)備难捌,它作為存儲(chǔ)在更大、也更慢的設(shè)備中的數(shù)據(jù)對(duì)象的緩沖區(qū)域鸦难。使用高速緩存的過程稱為緩存( caching根吁,讀作“ cashing")。
存儲(chǔ)器層次結(jié)構(gòu)的中心思想是合蔽,對(duì)于每個(gè)k击敌,位于k層的更快更小的存儲(chǔ)設(shè)備作為位于k+1層的更大更慢的存儲(chǔ)設(shè)備的緩存。換句話說拴事,層次結(jié)構(gòu)中的每一層都緩存來自較低一層的數(shù)據(jù)對(duì)象沃斤。
數(shù)據(jù)總是以塊大小為傳送單元( transfer unit)在第k層和第k+1層之間來回復(fù)制的。雖然在層次結(jié)構(gòu)中任何一對(duì)相鄰的層次之間塊大小是固定的刃宵,但是其他的層次對(duì)之間可以有不同的塊大小衡瓶。如上圖所示,L1和L0之間的傳送通常使用的是1個(gè)字大小的塊牲证。L2和L1之間(以及L3和I2之間哮针、I4和I3之間)的傳送通常使用的是幾十個(gè)字節(jié)的塊。而L5和L4之間的傳送用的是大小為幾百或幾千字節(jié)的塊坦袍。一般而言十厢,層次結(jié)構(gòu)中較低層(離CPU較遠(yuǎn))的設(shè)備的訪問時(shí)間較長(zhǎng),因此為了補(bǔ)償這些較長(zhǎng)的訪問時(shí)間键闺,傾向于使用較大的塊寿烟。
緩存命中
當(dāng)程序需要第k+1層的某個(gè)數(shù)據(jù)對(duì)象d時(shí),它首先在當(dāng)前存儲(chǔ)在第k層的一個(gè)塊中查找d辛燥。如果d剛好緩存在第k層中筛武,那么就是我們所說的緩存命中( cache hit)。
緩存不命中
另一方面挎塌,如果第k層中沒有緩存數(shù)據(jù)對(duì)象d徘六,那么就是我們所說的緩存不命中( cache miss)。當(dāng)發(fā)生緩存不命中時(shí)榴都,第k層的緩存從第k+1層緩存中取出包含d的那個(gè)塊待锈,如果第k層的緩存已經(jīng)滿了,可能就會(huì)覆蓋現(xiàn)存的一個(gè)塊嘴高。(緩存的替換策略:隨機(jī)替換替換策略竿音,最少被使用(LRU)替換策略)和屎。
緩存不命中種類
區(qū)分不同種類的緩存不命中有時(shí)候是很有幫助的。如果第k層的緩存是空的春瞬,那么對(duì)任何數(shù)據(jù)對(duì)象的訪問都會(huì)不命中柴信。一個(gè)空的緩存有時(shí)被稱為冷緩存( cold cache),此類不命中稱為強(qiáng)制性不命中( compulsory miss)或冷不命中( cold miss)宽气。冷不命中很重要随常,因?yàn)樗鼈兺ǔJ嵌虝旱氖录粫?huì)在反復(fù)訪問存儲(chǔ)器使得緩存暖身( warmed up)之后的穩(wěn)定狀態(tài)中出現(xiàn)萄涯。
緩存管理
存儲(chǔ)器層次結(jié)構(gòu)的本質(zhì)是绪氛,每一層存儲(chǔ)設(shè)備都是較低一層的緩存。在每一層上涝影,某種形式的邏輯必須管理緩存枣察。這里,我們的意思是指某個(gè)東西要將緩存劃分成塊袄琳,在不同的層之間傳送塊询件,判定是命中還是不命中,并處理它們唆樊。管理緩存的邏輯可以是硬件宛琅、軟件,或是兩者的結(jié)合逗旁。
2嘿辟、處理器解釋內(nèi)存中指令
2.1、系統(tǒng)硬件組成
經(jīng)過編譯片效,hello.c 源程序已經(jīng)被編譯成了可執(zhí)行目標(biāo)文件 hello,并存放在磁盤上红伦,那么如何運(yùn)行呢?
為了理解運(yùn)行 hello 程序時(shí)發(fā)生了什么淀衣,我們先要了解一個(gè)典型系統(tǒng)的硬件組織昙读。如下圖:
我們現(xiàn)在不需要對(duì)這張圖有很深入的理解,后面會(huì)詳細(xì)進(jìn)行介紹∨蚯牛現(xiàn)在先簡(jiǎn)單的認(rèn)識(shí)一下下面幾個(gè)主要部件:
一蛮浑、總線:貫穿整個(gè)系統(tǒng)的一組電子管道,通常被設(shè)計(jì)成用來傳送定長(zhǎng)的字節(jié)塊只嚣,也就是字沮稚。字的大小與系統(tǒng)相關(guān),比如在32位操作系統(tǒng)當(dāng)中册舞,一個(gè)字是4個(gè)字節(jié)蕴掏。
? 二、I/O設(shè)備:輸入/輸出(I/O)設(shè)備是系統(tǒng)與外部世界聯(lián)系通道,上圖有4個(gè)I/O設(shè)備盛杰。作為用戶輸入的鍵盤和鼠標(biāo)挽荡,作為用戶輸出的顯示器,以及用于長(zhǎng)期存儲(chǔ)數(shù)據(jù)和程序的磁盤饶唤。每一個(gè)I/O設(shè)備都通過一個(gè)控制器或者適配器與I/O總線相連徐伐。控制器是置于I/O設(shè)備本身的或者系統(tǒng)的主印刷電路板(通常稱為主板)上的芯片組募狂,而適配器則是一塊插在主板插槽上的卡。無論如何角雷,它們的功能都是在 I/O 總線和 I/O 設(shè)備之間傳遞信息祸穷。
? 三、主存:它是計(jì)算機(jī)中的一個(gè)臨時(shí)存儲(chǔ)設(shè)備勺三,在處理器執(zhí)行程序的時(shí)候雷滚,用來存放程序和程序處理的數(shù)據(jù)。物理上來說吗坚,主存是由一組動(dòng)態(tài)隨機(jī)存取存儲(chǔ)器(DRAM)組成的祈远,邏輯上來說,它是一個(gè)線性的字節(jié)數(shù)組商源,每一個(gè)字節(jié)都有唯一的地址(即數(shù)組索引)车份。
? 四、處理器:全稱中央處理器(CPU)牡彻,是解釋(或執(zhí)行)存儲(chǔ)在主存中指令的引擎扫沼。處理器的核心是一個(gè)字長(zhǎng)的存儲(chǔ)設(shè)備(或寄存器),簡(jiǎn)稱程序計(jì)數(shù)器(PC)庄吼,在任何時(shí)刻缎除,它都會(huì)指向主存中的某條機(jī)器指令(即含有該條指令的地址)。從系統(tǒng)通電到斷點(diǎn)总寻,處理器一直在不斷的執(zhí)行程序計(jì)數(shù)器所指向指令器罐,再更新程序計(jì)數(shù)器,使其指向下一條指令渐行。處理器所做的操作是圍繞主存轰坊、寄存器文件以及算術(shù)/邏輯單元(ALU)進(jìn)行的,寄存器文件是一個(gè)小的存儲(chǔ)設(shè)備殊轴,由一些1字長(zhǎng)的寄存器組成衰倦,每個(gè)寄存器都有唯一的名字。ALU則計(jì)算新的數(shù)據(jù)和地址值旁理。
CPU 在指令的要求下會(huì)做如下操作:
①樊零、加載:把一個(gè)字節(jié)或者一個(gè)字從主存復(fù)制到寄存器,以覆蓋寄存器原來的內(nèi)容
②、存儲(chǔ):把一個(gè)字節(jié)或者一個(gè)字從寄存器復(fù)制到主存的某個(gè)位置驻襟,以覆蓋這個(gè)位置上原來的內(nèi)容
③夺艰、操作:把兩個(gè)寄存器的內(nèi)容復(fù)制到 ALU,ALU 對(duì)這兩個(gè)字做算術(shù)操作沉衣,并把結(jié)果存放到一個(gè)寄存器中郁副,以覆蓋寄存器原來的內(nèi)容
④、跳轉(zhuǎn):從指令本身中抽取一個(gè)字豌习,并將這個(gè)字復(fù)制到程序計(jì)數(shù)器(PC)中存谎,以覆蓋PC中原來的內(nèi)容。
2.2肥隆、運(yùn)行hello程序
前面簡(jiǎn)單的介紹了系統(tǒng)的硬件組成和操作既荚,那么接下來介紹我們運(yùn)行程序時(shí)到底發(fā)生了什么。
? 想要在 Linux 系統(tǒng)中運(yùn)行該可執(zhí)行程序栋艳,我們要將它的文件名輸入到稱為外殼(shell)的應(yīng)用程序中恰聘,外殼是一個(gè)命令行解釋器,它輸出一個(gè)提示符吸占,等待你輸入一個(gè)命令晴叨,然后執(zhí)行這個(gè)命令。如果該命令行的第一個(gè)單詞不是一個(gè)內(nèi)置的外殼命令矾屯,那么外殼就會(huì)假設(shè)這是一個(gè)可執(zhí)行文件的名字兼蕊,它將加載并運(yùn)行這個(gè)文件。
初始時(shí)问拘,外殼程序執(zhí)行它的指令遍略,等待我們輸入一個(gè)命令。當(dāng)我們?cè)阪I盤上輸入字符串"./hello"后骤坐,外殼程序將字符逐一讀入到寄存器中绪杏,再把它放入到存儲(chǔ)器中,如下圖:
? 當(dāng)我們?cè)阪I盤上敲回車鍵的時(shí)候纽绍,外殼程序知道我們已經(jīng)結(jié)束了命令的輸入蕾久。然后外殼執(zhí)行一系列指令來加載可執(zhí)行的 hello 文件,將 hello 目標(biāo)文件中的代碼和數(shù)據(jù)從磁盤復(fù)制到主存拌夏。數(shù)據(jù)包括最終會(huì)被輸出的字符串“Hello World\n”僧著,一旦目標(biāo)文件中的代碼和數(shù)據(jù)被加載到主存,處理器就開始執(zhí)行 hello 程序的 main 程序中的機(jī)器語言指令障簿。這些指令將“Hello World\n” 字符串中的字節(jié)從主存復(fù)制到寄存器文件盹愚,再?gòu)募拇嫫魑募袕?fù)制到顯示設(shè)備,最終顯示在屏幕上站故。
3皆怕、操作系統(tǒng)管理硬件
程序不會(huì)直接訪問磁盤毅舆、顯示器等外設(shè),而是依靠操作系統(tǒng)提供的服務(wù)愈腾。所有應(yīng)用對(duì)硬件的操作嘗試都必須通過操作系統(tǒng)憋活。
操作系統(tǒng)有兩個(gè)基本功能:
- 防止硬件被失控的應(yīng)用程序?yàn)E用
- 向應(yīng)用程序提供簡(jiǎn)單一致的機(jī)制來控制復(fù)雜而大不相同的低級(jí)硬件設(shè)備
操作系統(tǒng)通過幾個(gè)抽象概念來實(shí)現(xiàn)這兩個(gè)功能,進(jìn)程虱黄、虛擬內(nèi)存和文件悦即。文件是對(duì) IO 設(shè)備的抽象表示,虛擬內(nèi)存是對(duì)主存和磁盤 IO 設(shè)備的抽象表示橱乱,進(jìn)程是對(duì)處理器辜梳、內(nèi)存和 IO 設(shè)備的抽象表示。
3.1泳叠、進(jìn)程
進(jìn)程是操作系統(tǒng)對(duì)一個(gè)正在運(yùn)行的程序的一種抽象冗美。 在一個(gè)系統(tǒng)上可以同時(shí)運(yùn)行多個(gè)進(jìn)程,而每個(gè)進(jìn)程都好像在獨(dú)占地使用硬件析二。
一個(gè) CPU 看上去像是在并發(fā)地執(zhí)行多個(gè)進(jìn)程,這是通過處理器在進(jìn)程間切換的機(jī)制(上下文切換)來實(shí)現(xiàn)對(duì)节预。
操作系統(tǒng)保持跟蹤進(jìn)程運(yùn)行所需的所有狀態(tài)信息叶摄,這種狀態(tài)就是上下文,包括 PC 和寄存器文件的當(dāng)前值以及主存的內(nèi)容安拟。
當(dāng)操作系統(tǒng)決定把控制權(quán)從當(dāng)前進(jìn)程轉(zhuǎn)移到某個(gè)新進(jìn)程時(shí)蛤吓,就會(huì)進(jìn)行上下文切換,即保存當(dāng)前進(jìn)程的上下文糠赦,恢復(fù)新進(jìn)程的上下文会傲,然后將控制權(quán)傳遞到新進(jìn)程。
從一個(gè)進(jìn)程到另一個(gè)進(jìn)程的切換是由操作系統(tǒng)的內(nèi)核(kernel)管理的拙泽,內(nèi)核是操作系統(tǒng)代碼常駐主存的部分淌山。它不是一個(gè)獨(dú)立的進(jìn)程,而是系統(tǒng)管理全部進(jìn)程所用代碼和數(shù)據(jù)結(jié)構(gòu)的集合顾瞻。
3.2泼疑、線程
一個(gè)進(jìn)程實(shí)際上由多個(gè)線程的組成,每個(gè)線程都運(yùn)行在進(jìn)程的上下文中荷荤,并共享同樣的代碼和數(shù)據(jù)退渗。
線程成為越來越重要的編程模型,因?yàn)槎嗑€程比多進(jìn)程之間更容易共享數(shù)據(jù)蕴纳,也因?yàn)榫€程一般來說都比進(jìn)程更高效会油。
3.3、虛擬內(nèi)存
虛擬內(nèi)存為每個(gè)進(jìn)程提供了一個(gè)假象古毛,即每個(gè)進(jìn)程都獨(dú)占地使用主存翻翩。每個(gè)進(jìn)程看到的內(nèi)存都是一致的,稱為虛擬地址空間。
每個(gè)進(jìn)程看到的虛擬地址空間由大量準(zhǔn)確定義的區(qū)構(gòu)成体斩,每個(gè)區(qū)都有專門的功能梭稚。
虛擬內(nèi)存的運(yùn)作需要硬件和操作系統(tǒng)軟件之間精密復(fù)雜的交互,包括對(duì)處理器生成的每個(gè)地址的硬件翻譯絮吵』】荆基本思想是把一個(gè)進(jìn)程虛擬內(nèi)存的內(nèi)容存儲(chǔ)在磁盤上,然后用主存作為磁盤的高速緩存蹬敲。
3.4暇昂、文件
文件就是字節(jié)序列,僅此而已伴嗡。 每個(gè) IO 設(shè)備急波,包括磁盤、鍵盤瘪校、顯示器澄暮,甚至網(wǎng)絡(luò),都可以看作文件阱扬。系統(tǒng)中的所有輸入輸出都是通過使用一組稱為 Unix I/O 的系統(tǒng)函數(shù)調(diào)用讀寫文件來實(shí)現(xiàn)的泣懊。
文件的概念簡(jiǎn)單精致,它向應(yīng)用程序提供了一個(gè)統(tǒng)一的視圖麻惶,來看待系統(tǒng)中可能含有的所有各式各樣的 I/O設(shè)備馍刮。
在 Linux 看來,一切皆文件窃蹋。
4卡啰、重要主題
4.1、Amdah1定律
Gene Amdahl,計(jì)算領(lǐng)域的早期先鋒之一警没,對(duì)提升系統(tǒng)某一部分性能所帶來的效果做出了簡(jiǎn)單卻有見地的觀察匈辱。這個(gè)觀察被稱為Amdahl定律(Amdahl’s law)。該定律的主要思想是惠奸,當(dāng)我們對(duì)系統(tǒng)的某個(gè)部分加速時(shí)梅誓,其對(duì)系統(tǒng)整體性能的影響取決于該部分的重要性和加速程度。
4.2佛南、并發(fā)和并行
? 我們用術(shù)語并發(fā)(concurrency)來指一個(gè)系統(tǒng)在同一時(shí)刻做多見事情梗掰,用術(shù)語并行(parallelism)指使用并發(fā)使系統(tǒng)運(yùn)行得更快。并行可以在一個(gè)系統(tǒng)的多個(gè)抽象層次被使用嗅回。我們這里強(qiáng)調(diào)三個(gè)層次及穗,我們系統(tǒng)抽象的高層向底層講。
- 線程級(jí)并發(fā)
- 指令集并行
- 單指令多數(shù)據(jù)并行
4.3绵载、系統(tǒng)中抽象重要性
? 對(duì)于操作系統(tǒng)埂陆,我們介紹了三個(gè)抽象:文件是I/O的抽象苛白,虛擬內(nèi)存是程序內(nèi)存的抽象,進(jìn)程是運(yùn)行時(shí)程序的抽象焚虱。這里我們?cè)黾右粋€(gè)新的抽象:虛擬機(jī)购裙,它是整個(gè)計(jì)算機(jī)的抽象,包括操作系統(tǒng)鹃栽,處理器躏率,程序。