第一章 計算機系統漫游
代碼段的生命周期
hello.c
#include
int main()
{
printf("hello world!\n");
return 0;
}
1.1 前序
源程序(源文件)實際上就是一個由0和1組成的位(又成比特bit)序列,8個位被組組成一組,稱為字節。每個字節表示程序中的某些文本字符(大部分的現代計算機系統都使用ASCII標準來表示文本字符)
1.2 編譯過程
hello.c -> 預處理器(cpp) -> hello.i(修改了源程序文本-將#include、宏 進行相應的替換) -> 編譯器(ccl) -> hello.s(翻譯成匯編程序文本) -> 匯編器(as) -> hello.o(翻譯成機器語言指令) -> 鏈接器(ld) -> hello(可執行文件)
1.3 系統硬件的執行流程
系統硬件的組成
1.總線
貫穿剩個系統的是一組電子管道,稱為總線,它攜帶信息字節并負責在各個部件間傳遞。通常總線被設計成傳遞定長的字節塊,也就是子(word).字重的字節數(即字長)是一個基本的系統參數,各個系統中都不盡相同.現在的大多數機器字節長要么是4個字節(32位),要么是8個字節(64位)
2.I/O設備
I/O(輸入/輸出)設備是系統與外部世界的聯系通道
3.主存
主存是一個臨時存儲設備,在處理器執行程序時,用來存放程序和程序處理的數據.從物理上來說,主存是由一組動態隨機存存取存儲器(DRAM)芯片組成的.從邏輯上來說,存儲器是一個線性的字節數組,每個字節都有其唯一的地址(數組索引),這些地址是從零開始的.一般來說,組成程序的每條機器指令都由不同數量的字節構成
4.處理器
中央單元處理器(CPU),簡稱處理器,是解釋(或執行)存儲在主存中指令的引擎.處理器的核心是一個為一個字的存儲設備(或寄存器),稱為程序計數器(PC).在任何時刻,PC都指向主存中的某條機器語言指令(即含有該條指令的地址)
從系統痛點開始,直到系統斷電,處理器一直在不斷地執行程序計算器指向的指令,在更新程序計數器,使其指向下一條指令.處理器看上去是按照一個非常簡單的執行模型來操作的,這個模型是由指令集架構決定的.這個模型中,指令按照嚴格的順序執行,而執行一條指令包含執行一系列步驟.處理器從程序計數器指向的內存處讀取指令,解釋執行中的位,執行指令指示的簡單操作,然后更新PC,使其指向下一條指令,而這條指令并不一定和內存中剛跟執行的指令相鄰.
這樣的簡單操作并不多,它們圍繞著主存、寄存器文件(register file)和算數/邏輯單元(ALU)進行.寄存器文件是一個小的存儲設備,由一些單個字長的寄存器組成,每個寄存器都有唯一的名字.ALU計算新的數據和地址值.下面是一些簡單的操作的例子,CPU在指令的要求下可能會執行這些操作
- 加載:從主存復制一個字節或者一個字到寄存器,以覆蓋寄存器原來的內容
- 存儲:從寄存器復制一個字節或者一個字到主存的某個位置,已覆蓋這個位置上原來的內容
- 操作:把兩個寄存器的內容復制到ALU,ALU對著兩個字做算術運算,并將結果存放到一個寄存器中,已覆蓋寄存器中原來的內容
- 跳轉:從指令本身抽取一個字,并將這個字復制到程序計數器(PC)中,以覆蓋PC中原來的值
1.4 存儲設備形成層次結構
在處理器和一個較大較慢的設備(例如主存)之間插入一個更小更快的存儲設備(例如告訴緩存)的想法已經成為一個普遍的觀念.實際上,每個計算機系統中的存儲設備都被組織成了一個存儲器層次結構,在這個層次結構中,從上至下,設備的訪問速度越來越慢,容量越來越大,并且每個字節的造價也越來越便宜.寄存器文件在層次結構中位于頂層,也就是第0級或記為L0.
1.5 操作系統硬件管理
操作系統有兩個基本的功能:
- 防止硬件被失控的應用程序濫用
- 向應用程序提供簡單一直的機制來控制復雜而又通常大不相同的低級硬件設備
操作系統通過幾個基本的抽象概念(進程、虛擬內存和文件)來實現這兩個功能

如上圖所示:文件是對I/O設備的抽象表示,虛擬內存是對主存和磁盤I/O設備的抽象表示,進程則是對處理器、主存和I/O設備的抽象表示
進程
```進程```是操作系統對一個正在運行的程序的一種抽象.在一個系統上可以同時運行多個進行,而每個進程都好像在獨占地使用硬件.而```并發運行```,則是說一個進程的指令和另一個進程的指令是交錯執行的.在大多數系統中,需要運行的進程數是多于可以運行他們的CPU個數的.傳統系統在一個時刻只能執行一個程序,而先進的多核處理器同時能夠執行多個程序,這是通過處理器在進程間切換來實現的.操作系統是新建這種交錯的機制稱為```上下文切換```
操作系統保持跟蹤進程運行所需的所有狀態信息.這種狀態,也就是上下文,包括許多信息,入PC和寄存器we年的當前值.當操作系統決定要把控制權從當前進程轉移到某個新進程時,就會進行上下文切換,即保存了當前進程的上下文、恢復新進程的上下文,然后將控制權傳遞到新進程.新進程就會從它上次停止的地方開始
線程
盡管通常我們認為一個進程只有單一的控制流,但是在現代系統中,一個進程實際上可以由多個稱為```線程```的執行單元組成,每個線程都運行在進行的上下文中,并共享同樣的代碼和全局數據.由于網絡服務器中對并行處理的需求,現場稱為越來越重要的編程模型,因為多線程之間比多進程之間更容易數據共享,也因為線程一般來說都比進程更高效.當有多處理器可用的時候,多線程也是一種使得程序可以運行的更快的方法
虛擬內存
虛擬內存是一個抽象的概念,它為每個進程提供了一個假象,即每個進程都在獨占地使用主存.每個進程看到的內存都是一致的,稱為```虛擬地址空間```.
在Linux中,地址空間最上面的區域是保留給操作系統中的代碼和數據的,這對所有進程來說都是一樣的.地址空間的底部區域存放用戶進行定義的代碼和數據(下圖中地址是從下往上增大的)
每個進程看到的虛擬地址空間由大量準確定義的區域構成,每個區都有專門的功能
- 程序代碼和數據:對所有的進程來說,代碼時從同一固定地址開始,緊接著是和C全局變量相對應的數據位置.代碼的數據區是直接按照可執行目標we年的內容初始化,在示例中就是可執行文件 hello.
- 堆:代碼和數據區后緊隨著的是運行時```堆```.代碼和數據區在進程一開始運行時就被制定了大小,與此不同,當調用了malloc和free這樣的C標準庫函數時,堆可以在運行時動態地擴展和收縮
- 共享庫:大約在地址空間的中間部分是一塊用來存放像C標準庫和數學庫的共享庫的代碼和數據的區域.共享庫的概念非常強大,也相當難懂
- 棧:位于用戶虛擬地址空間頂部的是```用戶棧```,編譯器用它來實現函數調用.和堆一樣,用戶棧在程序執行期間可以動態的擴展和收縮.特別的,每次我們調用一個函數時,棧會增長;從一個函數返回時,棧胡收縮
- 內核虛擬內存:地址空間頂部的區域是為了內核保留的.不允許應用程序讀寫這個區域的內容或者直接調用內核代碼定義的函數.相反,它們必須調用內核來執行這些操作
文件
文件就是字節序列,僅此而已.每個I/O設備,包括磁盤、鍵盤、顯示器、甚至網絡,都可以看成是文件.系統中的所有輸入輸出都是通過使用一小組稱為 Unix I/O的系統函數調用來讀寫文件實現的
文件這個簡單而精致的概念是非常強大的,因為它向應用程序提供了一個統一的視圖.
1.6 系統之間利用網絡通訊
現代系統經常通過網絡和其他系統連接到一起.從一個單獨的系統來看,網絡可以視為一個I/O設備.當系統從主存復制一串字節到網絡適配器時,數據流經過網絡到達另一臺機器,而不是比如說到達本地磁盤驅動器.相似地,系統可以讀取從其他機器發來的數據,并把數據復制到自己的主存.
隨著Internet這樣的全球網絡出現,從一臺主機復制信息到另外一臺主機已經成為計算機系統最重要的用途之一.例如:電子郵件、即時通訊、萬維網、FTP、和Telnet這樣的應用都是基于網絡復制信息的功能
1.9 Amdahl定律
