深入理解計算機系統——第01章——計算機系統漫遊

博客源自:http://blog.csdn.net/xuejianhui/article/details/52577937

1.1 信息就是位+上下文


初讀此書時,此標題對我觸動非常大,如醍醐灌頂!作者一針見血地道出了信息的本質。無論是磁盤中的文本文件、TCP報文協議、基於TCP封裝的HTTP報文協議等等,都是基於上下文。開頭告訴你怎麼解析、後面有多長的內容。GB2312、GBK、UTF-8等字符編碼得以區分,也是在文本開頭附加標誌。

源程序:就是一個由0和1組合的位(bit)序列,8位組成一字(byte),每個字節表示某個文本字符。

系統中所有的信息——包括磁盤文件、存儲器中的程序、存儲器中存放的用戶數據以及網絡上傳送的數據,都是由一串位表示的。區分不同數據對象的唯一方法是我們讀到這些數據對象時的上下文。

作爲程序員,我們需要了解數字的機器表示方式,因爲他們和實際的整數和實數是不同的。它們是對真值的有限近似值,有時候會有意向不到的行爲表現。見第 02 章詳解。

C語言的起源:
Dennis Ritchie在1969年~1973年創建的。
美國國家標準學會(American National Standards Institute,ANSI)在1989年頒佈了ANSI C標準,後來由國際標準化組織(International Standards Organization,ISO)負責C語言的標準化工作。
KernaghanRitchie合著的經典書被程序“K&R”。


1.2 程序被其他程序翻譯成不同格式

爲了在系統上運行hello.c程序,每條C語句都被編譯器轉化成一系列的低級機器語言指令。然後這些指令按照一種稱爲可執行目標程序的格式打好包,並以二進制磁盤文件的形式存放起來。目標程序也稱爲可執行目標文件

代碼-hello.c文件:

#include <stdio.h>

int main()
{
    printf("hello world\n");
}

在Unix系統上,從源文件到目標文件的轉化是由GCC編譯器驅動程序完成的:

unix> gcc -o hello hello.c

編譯系統

  • 預處理器(cpp)
    讀取系統頭文件stdio.h的內容,並把它直接插入到程序文本中。
    生成一個以.i爲後綴的文件。

  • 編譯器(ccl)
    將文本文件 hello.i 翻譯成文本文件 hello.s(以一種標準的文本格式保存的低級底層機器語言指令,被稱爲彙編程序) , 它包含一個彙編語言程序 (它爲不同高級語言的不同編譯器提供了通用的輸出語言)。

  • 彙編器(as)
    將 hello.s 翻譯成機器語言指令 , 把這些指令打包成一種叫做可重定位目標程序 ( relocatable object program ) 的格式 , 並將結果保存在目標文件hello.o中。
    hello.o 文件是一個二進制文件 , 它的字節編碼是機器語言指令而不是字符。 如果我們在文本編輯器中打開 hello.o 文件 , 看到的將是一堆亂碼 。

  • 鏈接器(ld)
    printf函數存在於一個名爲printf.o的單獨的預編譯好了的目標文件中 , 而這個文件必須以某種方式合併到我們的hello.o程序中 。鏈接器( ld ) 就 負責處理這種合併。
    結果就得到hello文件, 它是一個可執行目標文件 ( 或者簡稱爲可執行文件 ),可以被加載到內存中 , 由系統執行 。


《程序員的自我修養》中有更深入、更系統的講解。


1.3 瞭解編譯系統如何工作是大有益處的

程序員要知道編譯系統是如何工作的,原因如下:

  • 優化程序性能
    例如 , 一個 switch 語句是否總是比一系列的 if-then-else 語句高效得多?
    一個函數調用的開銷有多大?
    while 循環比 for 循環更有效嗎?
    指針引用數組索引更有效嗎?
    爲什麼將循環求和的結果放到一個本地變量中與將其放到一個通過引用傳遞過來的參數中相比 , 運行速度要快很多呢?
    爲什麼我們只是簡單地重新排列一下一個算術表達式中的括號就能讓一個函數運行得更快?

    第 05 章, 你將學習如何通過簡單轉換 C 語言代碼以幫助編譯器更好地完成工作 , 從而調整 C 程序的性能
    第 06 章, 你將學習到存儲器系統的層次結構特性 , C 語言編譯器將數組存放在存儲器中的方式, 以及 C 程序又是如何能夠利用這些知識從而更高效地運行。

  • 理解鏈接時出現的錯誤
    例如 , 鏈接器報告它無法解析一個引用這是什麼意思?
    靜態變量全局變量的區別是什麼 ?
    如果你在不同的 C 文件中定義了名字相同的兩個全局變量會發生什麼 ?
    靜態庫動態庫的區別是什麼 ?
    我們在命令行上排列庫的順序有什麼影響 ?
    最嚴重的是,爲什麼有些鏈接錯誤直到運行時纔會出現 ?

    第 07 章, 你將得到這些問題的答案。

  • 避免安全漏洞
    多年來 , 緩衝區溢出錯誤是造成大多數網絡和 Internet 服務器上安全漏洞 的主要原因 。 存在這些錯誤是因爲很少有人能理解限制他們從不受信任的站點接收數據的數量和格式的重要性。 學習安全編程的第一步就是理解數據和控制信息存儲在程序棧上的方式會引起的後果。作爲學習彙編語言的一部分, 我們將在第 03 章中描述堆棧原理緩衝區溢出錯誤。我們還將學習程序員 、編譯器和操作系統可以用來降低攻擊威脅的方法。


1.4 處理器讀並解釋存儲在存儲器中的指令

要想在 Unix 系統上運行該可執行文件 , 我們將它的文件名輸入到稱爲外殼 ( shell) 的應用程序中 :

unix> ./hello 
hello, world 
unix>

1.4.1 系統的硬件組成

爲了理解運行 hello 程序時發生了什麼 , 我們需要了解一個典型系統的硬件組織,下圖是 Intel Pentium系統產品系列的模型:
這裏寫圖片描述

  • 總線
    貫穿整個系統的是一組電子管道 , 稱做總線, 它攜帶信息字節並負責在各個部件間傳遞 。
    傳送定長的字節塊 , 也就是字 ( word )
    現在的大多數機器字長有的是 4 個字節 ( 32 位 ), 有的是 8 個字節 ( 64 位 )
    假設字長爲 4 個字節 , 並且總線每次只傳送 1 個字。

  • I/O設備
    每個 I/O 設備都通過一個控制器或適配器與 I/O 總線相連 。
    控制器適配器之間的區別主要在於它們的封裝方式
    控制器:置於 I/O 設備本身的或者系統的主印製電路板 ( 通常稱爲主板 ) 上的芯片組 ;
    適配器:則是一塊插在主板插槽上的卡。
    第 06 章會更多地說明磁盤之類的 I/O 設備是如何工作的。

  • 主存
    主存是一個臨時存儲設備 , 在處理器執行程序時 , 用來存放程序和程序處理的數據。
    物理上,是一組動態隨機存取存儲器 ( DRAM )芯片
    邏輯上 , 是一個線性的字節數組 , 每個字節都有其唯一的地址 ( 即數組索引 ), 這些地址是從零開始的

    例如 , 在運行 Linux 的 IA32 機器上 , short 類型的數據需要 2 個字節 , int 、 float 和 long 類型需要 4 個字節 , 而 double 類型需要 8 個字節 。

  • 處理器
    中央處理單元 ( CPU ), 簡稱處理器 , 是解釋 ( 或執行 ) 存儲在主存中指令的引擎
    處理器的核心是一個字長的存儲設備 (或寄存器), 稱爲程序計數器( PC )。在任何時刻 , PC都指向主存中的某條機器語言指令 (即含有該條指令的地址)。

    1.從系統通電開始 , 直到系統斷電 , 處理器一直在不斷地執行程序計數器指向的指令 , 再更新程序計數器 , 使其指向下一條指令。
    2.處理器看上去是按照一個非常簡單的指令執行模型來操作的 , 這個模型是由指令集結構決定的。
    3.在這個模型中, 指令按照嚴格的順序執行, 而執行一條指令包含執行一系列的步驟。
    3.1.處理器從程序計數器(PC)指向的存儲器處讀取指令;
    3.2.解釋指令中的位;
    3.3.執行該指令指示的簡單操作;
    3.4.然後更新PC, 使其指向下一條指令, 而這條指令並不一定與存儲器中剛剛執行的指令相鄰。

    操作是圍繞着主存寄存器文件 ( register file )算術 / 邏輯 單元 ( ALU )進行的 。
    寄存器文件是一個小的存儲設備 , 由一些1字長的寄存器組成, 每個寄存器都有唯一的名字 。 ALU 計算新的數據和地址值。
    下面列舉一些簡單操作的例子 , CPU 在指令的要求下可能會執行以下操作 :

    • 加載:把一個字節或者一個主存複製到寄存器 , 以覆蓋寄存器原來的內容。
    • 存儲:把一個字節或者一個寄存器複製到主存的某個位置 , 以覆蓋這個位置上原來的內容 。
    • 操作 : 把兩個寄存器的內容複製到ALU, ALU 對這兩個字做算術操作, 並將結果存放到 一個寄存器中 , 以覆蓋該寄存器中原來的內容 。
    • 跳轉 : 從指令本身中抽取一個, 並將這個複製到程序計數器(PC) 中 , 以覆蓋 PC中原來的值。

      第 03 章我們研究機器代碼時考慮的是機器的指令集結構所提供的抽象性。第 04 章將更詳細地介紹處理器 實際上是如何實現的 。

1.4.2 運行 hello 程序

這裏寫圖片描述

程序運行步驟大致如下:

1. 初始時,外殼程序執行它的指令,等待我們輸入一個命令;
2. 當我們在鍵盤上輸入字符串“./hello”後 , 外殼程序將字符逐一讀入寄存器 , 再把它存放到存儲器中;
3. 當我們在鍵盤上敲回車鍵時 , 外殼程序就知道我們已經結束了命令的輸入;
4. 然後外殼執行一系列指令來加載可執行的hello文件, 將 hello目標文件中的代碼和數據從磁盤複製到主存。 數據包括最終會被輸出的字符串“ hello, world\n ”。
5. 一旦目標文件 hello 中的代碼和數據被加載到主存, 處理器就開始執行 hello 程序的 main 程序中的機器語言指令;
6. 這些指令將“ hello, world\n ”字符串中的字節從主存複製到寄存器文件 , 再從寄存器文件中複製到顯示設備 , 最終顯示在屏幕上 。

另外,在第 06 章中利用直接存儲器存取 ( DMA) 的技術 , 數據可以不通過處理器而直接從磁盤到達主存 。如下圖:

這裏寫圖片描述


1.5 高速緩存至關重要

這個簡單的示例揭示了一個重要的問題 , 即系統花費了大量的時間把信息從一個地方挪到另 一個地方

hello 程序的機器指令最初是存放在磁盤上的 , 當程序加載時 , 它們被複制到主存 ; 當處理器運行程序時 , 指令又從主存複製到處理器。相似地 , 數據串 “ hello, world\n ” 初 始時在磁盤上 , 然後複製到主存 , 最後從主存上覆制到顯示設備 。 從程序員的角度來看 , 這些復 制就是開銷 , 減緩了程序 “ 真正 ” 的工作 。 因此 , 系統設計者的一個主要目標就是使這些複製操 作儘可能快地完成。

從程序員的角度來看 , 這些複製就是開銷 , 減緩了程序“ 真正 的工作。因此, 系統設計者的一個主要目標就是使這些複製操作儘可能快地完成。

這裏寫圖片描述


根據機械原理 , 較大的存儲設備要比較小的存儲設備運行得慢 , 而快速設備的造價遠高於同類的低速設備
例如 , 一個典型系統上的磁盤驅動器可能比主存大1000倍, 但是對處理器而言 , 從磁盤驅動器上讀取一個字的時間開銷要比從主存中讀取的開銷大1000萬倍
類似地 , 一個典型的寄存器文件只存儲幾百字節的信息 , 而主存裏可存放幾十億字節。然而處理器寄存器文件中讀數據的速度比從主存中讀取幾乎要快100倍

處理器主存之間的差距還在持續增大。加快處理器的運行速度比加快主存的運行速度要容易和便宜得多。
針對這個差異,系統設計者採用了更小 、更快的存儲設備 , 即高速緩存存儲器(簡稱高速緩存), 作爲暫時的集結區域,用來存放處理器近期可能會需要的信息。

這裏寫圖片描述

位於處理器芯片上的 L1 高速緩存的容量可以達到數萬字節 , 訪問速度幾乎和訪問寄存器文件一樣快。一個容量爲數十萬到數百萬字節的更大的 L2 高速緩存通過一條特殊的總線連接到處理器 。 進程訪問L2高速緩存的時間要比訪問L1高速緩存的時間長5倍, 但是這仍然比訪問主存的時間快5~10倍 。 L1和L2高速緩存是用一種叫做靜態隨機訪問存儲器(SRAM)的硬件技術實現的。比較新的 、處理能力更強大的系統甚至有三級高速緩存 : L1 、L2 和L3

第 06 章將講解這些重要的設備以及如何利用它們。


1.6 存儲設備形成層次結構

從上文講到,系統升級這正不遺餘力地縮短處理器與主存之間的速度差距,否則處理器會因爲等待主存而白白將部分資源浪費掉。
因此,根據存儲設備的速度暫時分爲下面這幾個層次,叫做存儲器層次結構。

存儲器層次結構的主要思想:一層上的存儲器作爲低一層的存儲器的高速緩存。

這裏寫圖片描述
不多扯了,通過書中給出的參數。它們彼此間的速度關係如下:

磁盤驅動器 * 1000萬倍 => 主存 * 5~10倍 => 高速緩存L2 * 5倍 => 高速緩存L1 * 2~4倍 => 寄存器

磁盤驅動器 * 1000萬倍 = 主存;
主存 * 5~10倍 = 高速緩存L2;
高速緩存L2 * 5倍 = 高速緩存L1;
高速緩存L1 * 2~4倍 = 寄存器;

程序員可以利用對此結構的理解提高程序性能,第 06 章將詳細討論這個問題。


1.7 操作系統管理硬件

以hello爲例,外殼和hello程序都沒有直接操作鍵盤、顯示器、磁盤或者主存,而是由操作系統提供服務。
操作系統有兩個基本功能:

  1. 防止硬件被失控的應用程序濫用;
  2. 嚮應用程序提供簡單一致的機制來控制複雜而又通常大相徑庭的低級硬件設備。

操作系統通過以下幾個基本的抽象概念來實現這兩個功能:

  • 文件:是對I/O設備的抽象表示;
  • 虛擬存儲器:是對主存和磁盤I/O設備的抽象表示;
  • 進程:是對處理器、主存和I/O設備的抽象表示。

Unix和Posix
這裏給出幾個貝爾實驗室的牛人,大家自行搜索他們的牛逼事蹟吧。
Ken ThompsonDennis RitchieDoug McllroyJoe Ossanna等參與了Honeywell的Multics項目,Multics因過於複雜而告終,Unix算是更小、更簡單的版本。
Brian Kernighan是Unix的命名者,並暗自Multics過於複雜。
Richard Stallman創建了Posix標準,並使得Unix更加標準化。

這裏寫圖片描述

1.7.1 進程

操作系統會提供一種假象,就好像系統上只有這個程序在運行,看上去只有這個程序在使用處理器、主存和I/O設備。
圖中,這種交錯執行的機制叫做上下文切換
此處只考慮包含一個CPU的單核處理器的情況,將在1.9.1節討論多處理器系統。
操作系統保持跟蹤進程運行所需要的所有狀態信息。這種狀態,叫做上下文,它包括許多信息,例如PC和寄存器文件的當前值,以及主存的內容。在任何一個時刻,單處理器內容都只能執行一個進程的代碼。

這裏寫圖片描述

示例場景中有兩個併發的進程:外殼進程和hello進程。
起初,只有外殼進程在運行,即等待命令行的輸入。當我們讓它運行hello程序時,外殼通過調用一個專門的函數,即系統調用,來執行我們的請求,系統調用會將控制權傳遞給操作系統。操作系統保存外殼進程的上下文,創建一個新的hello進程及其上下文,然後將控制權傳遞給新的hello進程。hello進程終止後,操作系統恢復外殼進程的上下文,並將控制權回給它,外殼進程將繼續等待下一個命令行輸入。

將在第 08 章揭示這項工作的原理。

1.7.2 線程

此處篇幅比較小,都是比較基礎,因爲本書從最底層講起,因此在第 12 章才能看到與併發相關的內容。

由於網絡服務器對並行處理的需求,線程成爲越來越重要的編程模型,因爲多線程之間比多進程之間更容易共享數據,也因爲線程一般來說都比進程更高效。當有多個服務器可用的時候,多線程也是一種使程序可以更快運行的方法。


題外話:在實際編程中,線程比進程更高效,並不絕對。因爲鎖的干擾,當業務過於複雜時,可能會導致線程頻繁地等待鎖甚至死鎖。比如chrome就是爲了避開死鎖,而選擇進程,使用管道作爲進程間通信的方式(管道通信雖然較冷門,但卻非常強大,尤其是window的有名管道)。

1.7.3 虛擬存儲器

虛擬存儲器是一種抽象概念,它提供了一種假象,即每個進程都在獨佔地使用內存。每個進程看到的是一致的存儲器,稱爲虛擬地址空間(還有些翻譯籠統地稱爲虛擬內存)。

第 07 章,將詳細討論。此處請注意“共享庫的存儲器映射區域”,這裏少有人關注。

這裏寫圖片描述

從最低地址開始,從下到上,分別是:

  • 程序代碼和數據:可執行目標文件和C 全局變量。一開始就被規定好的大小。
  • :通過malloc和free動態地擴展和收縮,C++建議用new和delete,對抽象對象支持更好,比如會默認調用構造函數和析構函數。且據《Effective C++》上說,new的存儲位置與malloc是不同的。
  • 共享庫:中間位置存放C標準庫數學庫等共享庫的程序代碼和數據的區域。
  • :編譯器用它來實現函數調用,每次調用一個函數時,棧增長;從一個函數返回時,棧收縮。
  • 內核虛擬存儲器:內核總是駐留在內存中,是操作系統的一部分。地址空間頂部的區域是爲內核保留的,不允許應用程序讀寫這個區域的內容或者直接調用內核代碼定義的函數。


後續結合《Effective C++》、《C Primer Plus》和《UNIX環境高級編程》詳細介紹下。

1.7.4 文件

文件就是字節序列,因此而已。每個I/O設備都可視爲文件,系統中所有輸入輸出都是通過使用一小組成爲Unix I/O的系統函數調用讀寫文件來實現的。詳情見第 10 章


《UNIX環境高級編程》中,有一個文件描述符的概念,類似於Windows的句柄。Unix開篇就說——Everything is a file。


1.8 系統之間利用網絡通信

這裏寫圖片描述

繼續以hello爲例,我們可以使用telnet應用在一個遠程主機上運行hello程序。假設用本地主機上的telnet客戶端連接遠程主機上的telnet服務端。在我們登錄到遠程主機並運行外殼後,遠程的外殼就在等待接收輸入命令。

這裏寫圖片描述

圖中已將過程描述的非常清楚,不再贅述了。


對telnet的介紹不錯,寥寥數語清楚明確地道出telnet的原理,有大家風範!


1.9 重要主題

1.9.1 併發和並行

數字計算機的整個歷史中,有兩個需求是驅動進步的而持續動力:

  • 我們想要計算機做得更多
  • 我們想要計算機運行的更快

併發(concurrency):指一個同時具有多個活動的系統;
並行(parallelism):指用併發使一個系統運行得更快。

1. 線程級併發

構建進程這個抽象,我們能夠設計出同時執行多個程序的系統,這就導致了併發。
使用線程,我們甚至能夠在一個進程中執行多個控制流。從20世紀60年代初期出現分時(time-sharing)以來,計算機系統就開始有了對併發執行的支持。

題外話:《圖解TCP/IP》中在講解網絡發展歷程中也提到了分時系統對網絡方案變更的影響。這本書以網絡發展歷程爲軸,講解了每個新技術的出現背景、作用和原理,幾乎只看圖就可以瞭解《TCP/IP協議》裏的內容。另外,此書與另外《圖解HTTP》、《圖解網路硬件》併成爲圖解三部曲,《圖解服務器網絡架構》也不錯。

多處理器系統:由單個操作系統內核控制多處理器的系統。

多核處理器:將多個CPU(稱爲)集成到一個集成電路芯片上。工業界專家預言最終將會有上百個核集成到一個芯片上。

這裏寫圖片描述

超線程,有時稱爲同時多處線程(simultaneous multi-threading),是一項允許一個CPU執行多個控制流的技術。它涉及到CPU某些硬件有多個備份,比如程序計數器和寄存器文件;而其他的硬件部分只有一份,比如執行浮點算術運算的單元。
常規的處理器需要大約2萬個時鐘週期做不同線程的轉換,而超線程的處理器可以在單個週期的基礎上決定要執行哪一個線程。這使得CPU能夠更好地利用它的資源。
例如,假設一個線程必須等到某些數據被轉載到高速緩存中,那CPU就可以繼續去執行另一個線程。舉例說明,Intel Core i7處理器可以讓一個核執行兩個線程,所以一個4核的系統實際上可以並行地執行8個線程。

這裏寫圖片描述

多處理器的使用可以從兩個方面提高系統性能:

  • 它減少在執行多個任務時模擬併發的需要;
  • 它可以使程序運行得更快。當然,要以多線程方式來寫程序,這些線程可以並行地高效執行。

直到多核和超線程系統的出現才極大地激發了人們的一種願望,即找到書寫應用程序的方法利用硬件開發線程級並行性。

第 12 章將更深入地探討併發。

2. 指令級並行

指令級並行:在較低的抽象層面上,現代處理器可以同時執行多條指令的屬性。

如1978年的Intel 8086,需要多個(通常是3~10個)時鐘週期來執行一條指令,比較先進的處理器可以保持每個時鐘週期2~4條指令的執行速度。其實每條指令從開始到結束需要長得多的時間,大約20個或更多的週期。

流水線(pipelining) 中,將執行一條指令所需要的活動劃分爲不同的步驟,將處理器的硬件組織成一系列的階段,每個階段執行一個步驟。這些階段可以並行地操作,用來處理不同指令的不同部分。我們會看到一個相當簡單的硬件設計,它能夠達到接近一個時鐘週期一條指令的執行速率。第 04 章將更深入地探討流水線。

超標量(superscalar):處理器達到比一個時鐘週期一條指令更快的的執行速率。
第 05 章將介紹超標量處理器的高級模型。

3. 單指令 、 多數據並行

在最低層次上,許多現在處理器擁有特殊的硬件,允許一條指令產生多個可以併發執行的操作,這種方式稱爲單指令、多數據,即SIMD並行

提供這些 SIMD 指令多是爲了提高處理影像、聲音和視頻數據應用的執行速度。雖然有IE編輯器視圖從 C 程序中自動抽取 SIMD 並行性,但是更可靠的方法是使用編譯器支持的特殊向量數據類型來寫程序,例如GCC就支持向量數據類型。

1.9.2 計算機系統中抽象的重要性

這裏寫圖片描述

注:計算機系統中的一個重大主題就是提供不同層次的抽象表示,來隱藏實際實現的複雜性。


1.10 小結

計算機系統是有硬件和系統軟件組成的,他們共同協作來運行應用程序。計算機內部的信息被表示爲一組組長的位,它們依據上下文有不同的解釋方式。程序被其他程序翻譯成不同的形式,開始時是ASCII文本,然後被編譯器和鏈接器翻譯成二進制可執行文件。

處理器讀取並解釋存放在主存裏的二進制指令。因爲計算機把大量時間用於存儲器、I/O設備和CPU寄存器之間複製數據,所以將系統中的存儲設備劃分成層次結構——CPU寄存器在頂部,接着是多層硬件高速緩存存儲器、DRAM主存和磁盤存儲器。在層次模型中,位於更高層的存儲設備比底層的存儲設備要更快,單位比特開銷也更高。層次結構中較高層次的存儲設備可以作爲較低層次設備的高速緩存。通過理解和運用這種存儲層次結構的知識,程序員可以優化 C 程序的性能。

操作系統內核是應用程序和硬件之間的媒介。它提供三個基本的抽象:

  • 文件是對I/O設備的抽象
  • 虛擬存儲器是對主存的磁盤的抽象
  • 進程是對處理器、主存和I/O設備的抽象

最後,網絡提供了計算機系統之間的通信手段。從特殊系統的角度來看,網絡就是一種I/O設備。


參考文獻說明

Ritchie 寫了關於早期 C 和 Unix 的有趣的第一手資料 [87, 88]。
Ritchie 和 Thompson 提供了 最早出版的 Unix 資料 [89]。
Silberschatz 、 Gavin 和 Gagne[98] 提供了關於 Unix不同版本的詳盡歷史。
Posix 標準可以在線獲得 ( www.unix.org )。


所有章節內容:

第 01 章:計算機系統漫遊
第 02 章:信息的表示和處理
第 03 章:程序的機器級表示
第 04 章:處理器體系結構
第 05 章:優化程序性能
第 06 章:存儲器層次結構
第 07 章:鏈接
第 08 章:異常控制流
第 09 章:虛擬存儲器
第 10 章:系統級I/O
第 11 章:網絡編程
第 12 章:併發編程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章