2020-12-24《重學作業系統——上》林䭽 前阿里巴巴高階技術專家(P8)

永不言敗2020發表於2020-12-24

只做最精煉的知識,讓記憶更加深刻,讓面試見鬼去吧!!!


《重學作業系統》是前阿里巴巴高階技術專家,高階架構師(P8)林䭽  在Lagou教育平臺上開設的course,時間比較長,共 8 個模組,合計 39 個課時,為精煉重點,幫助快速消化吸收,想整理出上下兩部分。

開篇詞 | 為什麼大廠面試必考作業系統?(瞭解)

任何研發工具學下去也都會碰到作業系統,比如:

MySQL 深入學下去會碰到 InnoDB 檔案系統;HBase 深入學下去會有 Hadoop 檔案系統(HDFS);Redis 深入學下去會碰到 Linux 的I/O模型

Docker 深入學下去有 Linux 的名稱空間等;甚至 Spring 框架,也需要用到執行緒池和排程演算法

面試官,我們需要通過作業系統知識判斷求職者的綜合能力,你可以將這些語言、開發工具用到什麼層次?是能夠使用還是理解原理,甚至具備系統改造的能力

學習目標有兩個:一是幫助你順利通過面試、跳槽漲薪;另一個是幫助你提升應對實際工作場景的能力,具體包括以下幾點。

提升學習和理解能力:比如學習 Redis 可以理解到日誌檔案系統層面;學習 Java/Python/Node 等語言可以理解到語言最底層

提升應用架構能力:比如可以將作業系統的微核心架構遷移到自己設計的系統中。

提升系統穩定性架構能力:比如在多執行緒設計上更出色,可以幫助同事找到設計漏洞

提升運維能力:做到可以方便地管理叢集和分析日誌

這門課程對標的是架構師層級的基礎能力,看個人的接受程度,精選了 80 道左右的大廠面試題,國內大廠研發崗位最為關心的問題,也是大廠面試的熱門問題,學完之後大概會在阿里的 P7 及以上層級拉開個人薪資和團隊整體水平差異的分水嶺,根本原因就是計算機基礎知識的掌握程度,個人能力的高低決定了收入的水平。

課前必讀 | 構建知識體系,可以這樣做!(知道)

課程內容&知識體系

我們先來看下這門課程的知識體系結構,分為 8 個模組,39 個課時,具體如下。

模組一:(前置知識)計算機組成原理。 如果你對計算機的組成原理中涉及的比如記憶體、暫存器工作原理、CPU 指令、匯流排都是怎麼工作的這些基本問題,沒有搞清楚,大概率會影響你後續對作業系統的學習。因此,在課程開始前,我先來給你一份作業系統的前置知識,幫助你更好地理解後續內容。

模組二:(初探)Linux 指令入門。 這個模組將介紹一些實用的知識,帶你入門 Bash 程式設計,並通過日誌分析、效能監控、叢集管理等實戰場景深入學習 Linux 指令。這些對於日常開發和運維人員來說,都會非常有幫助。

模組三:(總綱)作業系統概述。 這部分幫助你瞭解作業系統的整體設計,介紹核心、使用者空間等基本概念,還會介紹作業系統的分類,以及對比一下市面上的作業系統(如 Windows、Linux、Unix、Android 等),讓你對整個作業系統生態能有一個整體的認識。

總的來說,模組四 ~ 模組七是我們這門課程的核心內容,也是面試的重點考區。設定這塊內容的目的是藉助作業系統的知識,幫你思考如何解決實戰問題,比如我們反覆提及的高併發、資料一致性、大資料儲存和網路問題等。

模組四:(面試重點)程式和執行緒。 我會針對大家在面試和工作中最常見的併發和資料同步問題,從程式原理、多執行緒程式設計、互斥和樂觀鎖、死鎖和飢餓、排程演算法、程式通訊等多個方面,同時結合一些語言特性(比如 Java 的語言特性)講解原理、思考方案及對策。

模組五:(面試重點)記憶體管理。 這部分我們是從頁表和 MMU、虛擬化、記憶體的分配和回收、快取置換、逃逸分析、三色演算法、生代演算法等方面入手,幫助你瞭解記憶體的工作原理,應對高併發帶來的記憶體使用問題。

模組六:(面試重點)檔案系統。 這部分內容我們將從兩個方面入手,一方面是通過學習 Linux 的檔案目錄結構,瞭解 Linux 下不同的檔案目錄的功能和作用,幫助你把 Linux 用好;另一個方面,從檔案系統的底層設計入手,幫助你瞭解檔案系統的設計思路和原理,並且通過講解資料庫的檔案系統,比如 MySQL 的 InnoDb、B+Tree 以及 Hadoop 的 HDFS,幫你把檔案系統的知識應用到處理海量資料的領域。

模組七:(面試重點)網路與安全。 這部分講解面試中常見的網際網路協議群、TCP 和 UDP 協議Linux 的 I/O 模型公私鑰加密體系,以及一些最基本的計算機網路安全知識,幫助你理解作業系統和網路之間的互動,從而更好地利用作業系統知識設計業務系統的網路架構。

模組八:(知識擴充)虛擬化和其他。 最後這部分,我們將從作業系統的角度學習容器化應用(比如 Kubernetes 和 Docker),還會深入討論 Linux 架構及商業作業系統。這些知識一方面能夠幫你和麵試官產生更多的共鳴,另一方面還能幫你開拓視野、開啟思路,看到未來的發展趨勢。

梳理一下作業系統整體的知識框架,幫你掃除知識盲區。

從知識結構上來看,作業系統最核心的部分是程式,因為作業系統自己不能提供服務,它要想實現價值,就必須通過安裝在系統中的應用程式。而安裝好的應用程式,啟動後就成了程式,所以說程式處在作業系統知識體系的核心。

瞭解了以上內容後,我們圍繞程式繼續梳理,可以發現:

程式往往要同時做很多事情,比如瀏覽器同時要處理網路、又要處理滑鼠、還要展示內容,因此有了多執行緒的概念。

程式需要執行用的儲存空間,比如需要存程式指令、需要堆疊存執行資料,因此需要記憶體

程式需要將一部分資料持久的儲存下來,因此需要檔案系統

程式需要和外界通訊,其中一種途徑就是網路

開發過程中我們希望程式可以單獨部署,於是需要容器

作業系統核心本身也是一個程式,可以理解成一個程式,它同樣是需要單獨研究的。

所以,程式是核心核心、多執行緒、記憶體、檔案系統、網路、容器和虛擬是配套的能力。

思考:程式本身是做什麼的?

答:程式是程式的執行副本,作業系統用程式來分配資源。(先記住,待補充)

學習方法:遇到不懂的,我該如何解決自己的問題(思維導圖法)?

程式設計師最重要的是搜尋知識的能力,我非常贊同這個說法,此外,我認為如果你想要長遠發展,還應同時具備用結構化的思維去構建知識體系的能力。因為知識成體系後,會形成關聯記憶和整體的理解,這種經過深度思考和梳理過的知識才能轉化為自己的儲備。

下面請你跟我一起進入到場景中,跟著我的思路把你的大腦運轉起來。假設,在工作的過程中,我遇到了一塊不懂的知識,其中有一個技術名詞我不瞭解它的作用,比如 ReentrantLockLock,那麼我該如何解決自己的問題呢?

注意: 你也可以把它替換成任意一個陌生的或者你不理解的技術名詞。

首先我會去查閱它的官方文件,然後發現了以下這些線索:

建構函式上有個引數在配置鎖的公平性;

ReentrantLockLock 是可重入的;

功能類似 synchronized 關鍵字,但是更靈活;

支援 lock、unlock、tryLock 等方法;

底層是 AbstractQueuedSynchronizer。

接著,根據我獲得的知識,追溯 synchronized 關鍵字,發現 ReentrantLockLock 都說自己的底層是 AbstractQueuedSynchronizer(AQS),我感覺到 AQS 應該是一個重要的東西。

然後我會去查資料驗證我的猜測。這時候,我又得到了一個新的資訊:發現AQS是用來實現訊號量、條件變數以及其他鎖的一個程式設計框架

假設我還不知道訊號量、條件變數和鎖是什麼,於是我通過搜尋資料,發現這些名詞通通指向一門科學,也就是作業系統

接下來,我會去挑選一門講作業系統的線上課程或者買一本書來查閱,經過查閱發現這些名詞出現在程式和多執行緒這個部分。然後我翻閱了這兩個章節的內容,發現了更多我不知道的知識,比如死鎖和飢餓、訊號量、競爭條件和臨界區、互斥的實現,以及最底層的 CPU 指令

經過以上過程的推導,我開始在腦海中梳理這些知識點,然後動筆畫出了一幅基於思考過程的思維導圖,將這些知識點串聯起來,如下圖所示:

這時候,我發現公平鎖、可重入鎖其實都是鎖的一種實現,而 Java 中實現鎖這個機制用的是 AQS,而 AQS 最基本的問題是要解決資源競爭的問題

通過學習,我發現資源競爭的問題在作業系統裡叫作競爭條件,解決方案是讓臨界區互斥。讓臨界區互斥可以用演算法的實現,但是為了執行效率,更多的情況是利用 CPU 指令。Java 裡用於實現互斥的原子操作 CAS,也是基於 CPU 指令的。

作業系統在解決了互斥問題的基礎上,還提供了解決更復雜問題的資料結構,比如說訊號量、競爭條件等;而程式語言也提供了資料結構,比如說可重入鎖、公平鎖

 

模組一:(前置知識)計算機組成原理


01 | 計算機是什麼:“如何把程式寫好”這個問題是可計算的嗎?

答:計算機能力也是有邊界的。哥德爾的不完備性定理,讓大家看到了世界上還有大量不可計算的問題。哪些問題可以被計算,哪些不可以被計算,這就是可計算性理論,我們可以把世界上想解決的事情都稱作問題,解決問題往往需要消耗晶片的計算能力,這通常稱作時間開銷,另外解決問題還需要消耗記憶體,稱作空間開銷。從絕對的對錯角度去看,這是一個不可計算問題,因為它沒有辦法被完全解決;但是從圖靈測試層面來看,雖然目前無法解決這個問題,但是我們有理由相信,在未來,計算機對這個問題的解決方案,是可以超過人類的。

02 | 程式的執行:相比 32 位,64 位的優勢是什麼?(上)

答:沒有說清楚 32、64 位指的是作業系統、是軟體、還是 CPU?如果是軟體,那麼我們的資料庫有 32 位和 64 位版本;如果是作業系統,那麼在阿里雲上選擇 Centos 和 Debian 版本的時候,也會有 32/64 版本;如果是 CPU,那麼有 32 位 CPU,也有 64 位 CPU。

馮諾依曼模型

 

計算機結構分成以下 5 個部分:輸入裝置;輸出裝置;記憶體;中央處理器;匯流排。這個模型也被稱為馮諾依曼模型,下面我們具體來看看這 5 部分的作用。

記憶體

在馮諾依曼模型中,程式和資料被儲存在一個被稱作記憶體的線性排列儲存區域。儲存的資料單位是一個二進位制位,英文是 bit。最小的儲存單位叫作位元組,也就是 8 位,英文是 byte,每一個位元組都對應一個記憶體地址。記憶體地址由 0 開始編號,比如第 1 個地址是 0,第 2 個地址是 1, 然後自增排列,最後一個地址是記憶體中的位元組數減 1。

我們通常說的記憶體都是隨機存取器,也就是讀取任何一個地址資料的速度是一樣的,寫入任何一個地址資料的速度也是一樣的。

CPU

馮諾依曼模型中 CPU 負責控制和計算。為了方便計算較大的數值,CPU 每次可以計算多個位元組的資料。

如果 CPU 每次可以計算 4 個 byte,那麼我們稱作 32 位 CPU;如果 CPU 每次可以計算 8 個 byte,那麼我們稱作 64 位 CPU。這裡的 32 和 64,稱作 CPU 的位寬

為什麼 CPU 要這樣設計呢? 因為一個 byte 最大的表示範圍就是 0~255。比如要計算 20000*50,就超出了byte 最大的表示範圍了。因此,CPU 需要支援多個 byte 一起計算。當然,CPU 位數越大,可以計算的數值就越大。但是在現實生活中不一定需要計算這麼大的數值。比如說 32 位 CPU 能計算的最大整數是 4294967295,這已經非常大了。

控制單元和邏輯運算單元

CPU 中有一個控制單元專門負責控制 CPU 工作;還有邏輯運算單元專門負責計算。具體的工作原理我們在指令部分給大家分析。

暫存器

CPU 要進行計算,比如最簡單的加和兩個數字時,因為 CPU 離記憶體太遠,所以需要一種離自己近的儲存來儲存將要被計算的數字。這種儲存就是暫存器暫存器就在 CPU 裡,控制單元和邏輯運算單元非常近,因此速度很快。

暫存器中有一部分是可供使用者程式設計用的,比如用來存加和指令的兩個引數,是通用暫存器

還有一部分暫存器有特殊的用途,叫作特殊暫存器。比如程式指標,就是一個特殊暫存器。它儲存了 CPU 要執行的下一條指令所在的記憶體地址。注意,程式指標不是儲存了下一條要執行的指令,此時指令還在記憶體中,程式指標只是儲存了下一條指令的地址

下一條要執行的指令,會從記憶體讀入到另一個特殊的暫存器中,這個暫存器叫作指令暫存器。指令被執行完成之前,指令都儲存在這裡

匯流排

CPU 和記憶體以及其他裝置之間,也需要通訊,因此我們用一種特殊的裝置進行控制,就是匯流排。匯流排分成 3 種:

一種是地址匯流排,專門用來指定 CPU 將要操作的記憶體地址。還有一種是資料匯流排,用來讀寫記憶體中的資料。當 CPU 需要讀寫記憶體的時候,先要通過地址匯流排來指定記憶體地址,再通過資料匯流排來傳輸資料。最後一種匯流排叫作控制匯流排用來傳送和接收關鍵訊號,比如後面我們會學到的中斷訊號,還有裝置復位、就緒等訊號,都是通過控制匯流排傳輸。同樣的,CPU 需要對這些訊號進行響應,這也需要控制匯流排。

輸入、輸出裝置

輸入裝置向計算機輸入資料,計算機經過計算,將結果通過輸出裝置向外界傳達。如果輸入裝置、輸出裝置想要和 CPU 進行互動,比如說使用者按鍵需要 CPU 響應,這時候就需要用到控制匯流排。

到這裡,相信你已經對馮諾依曼模型的構造有了一定的瞭解。這裡我再強調幾個問題:

1. 線路位寬問題
第一個問題是,你可能會好奇資料如何通過線路傳遞。其實是通過操作電壓,低電壓是 0,高電壓是 1。

如果只有一條線路,每次只能傳遞 1 個訊號,因為你必須在 0,1 中選一個。比如你構造高高低低這樣的訊號,其實就是 1100,相當於你傳了一個數字 10 過去。大家注意,這種傳遞是相當慢的,因為你需要傳遞 4 次。

這種一個 bit 一個 bit 傳送的方式,我們叫作序列。如果希望每次多傳一些資料,就需要增加線路,也就是需要並行

如果只有 1 條地址匯流排,那每次只能表示 0-1 兩種情況,所以只能操作 2 個記憶體地址;如果有 10 條地址匯流排,一次就可以表示 210 種情況,也就是可以操作 1024 個記憶體地址;如果你希望操作 4G 的記憶體,那麼就需要 32 條線,因為 232 是 4G。

到這裡,你可能會問,那我序列傳送行不行?當然也不是不行,只是速度會很慢,因為每多增加一條線路速度就會翻倍。

2. 64 位和 32 位的計算
第二個問題是,CPU 的位寬會對計算造成什麼影響?

我們來看一個具體場景:要用 32 位寬的 CPU,加和兩個 64 位的數字。

32 位寬的 CPU 控制 40 位寬的地址匯流排、資料匯流排工作會非常麻煩,需要雙方制定協議。 因此通常 32 位寬 CPU 最多操作 32 位寬的地址匯流排和資料匯流排。

因此必須把兩個 64 位數字拆成 2 個 32 位數字來計算,這樣就需要一個演算法,比如用像小時候做加法豎式一樣,先加和兩個低位的 32 位數字,算出進位,然後加和兩個高位的 32 位數字,最後再加上進位。

而 64 位的 CPU 就可以一次讀入 64 位的數字,同時 64 位的 CPU 內部的邏輯計算單元,也支援 64 位的數字進行計算。但是你千萬不要僅僅因為位寬的區別,就認為 64 位 CPU 效能比 32 位高很多。

要知道大部分應用不需要計算超過 32 位的數字,比如你做一個電商網站,使用者的金額通常是 10 萬以下的,而 32 位有符號整數,最大可以到 20 億。所以這樣的計算在 32 位還是 64 位中沒有什麼區別。

還有一點要注意,32 位寬的 CPU 沒辦法控制超過 32 位的地址匯流排、資料匯流排工作。比如說你有一條 40 位的地址匯流排(其實就是 40 條線),32 位的 CPU 沒有辦法一次給 40 個訊號,因為它最多隻有 32 位的暫存器。因此 32 位寬的 CPU 最多操作 232 個記憶體地址,也就是 4G 記憶體地址。

總結
關於計算機組成和指令部分,我們就先學到這裡。這節課我們通過圖靈機和馮諾依曼模型學習了計算機的組成、CPU 的工作原理

03 | 程式的執行:相比 32 位,64 位的優勢是什麼?(下)

程式的執行過程

當 CPU 執行程式的時候:

1.首先,CPU 讀取 PC 指標指向的指令,將它匯入指令暫存器。具體來說,完成讀取指令這件事情有 3 個步驟:

步驟 1:CPU 的控制單元操作地址匯流排指定需要訪問的記憶體地址(簡單理解,就是把 PC 指標中的值拷貝到地址匯流排中)。

步驟 2:CPU 通知記憶體裝置準備資料(記憶體裝置準備好了,就通過資料匯流排將資料傳送給 CPU)。

步驟 3:CPU 收到記憶體傳來的資料後,將這個資料存入指令暫存器。

完成以上 3 步,CPU 成功讀取了 PC 指標指向指令,存入了指令暫存器。

2.然後,CPU 分析指令暫存器中的指令,確定指令的型別和引數。
3.如果是計算型別的指令,那麼就交給邏輯運算單元計算;如果是儲存型別的指令,那麼由控制單元執行。
4.PC 指標自增,並準備獲取下一條指令。

比如在 32 位的機器上,指令是 32 位 4 個位元組,需要 4 個記憶體地址儲存,因此 PC 指標會自增 4。

記憶體雖然是一個隨機存取器,但是我們通常不會把指令和資料存在一起,這是為了安全起見。具體的原因我會在模組四程式部分展開講解,歡迎大家在本課時的留言區討論起來,我會結合你們留言的內容做後續的課程設計。

程式指標也是一個暫存器,64 位的 CPU 會提供 64 位的暫存器,這樣就可以使用更多記憶體地址。特別要說明的是,64 位的暫存器可以定址的範圍非常大,但是也會受到地址匯流排條數的限制。比如和 64 位 CPU 配套工作的地址匯流排只有 40 條,那麼可以定址的範圍就只有 1T,也就是 240。

從 PC 指標讀取指令、到執行、再到下一條指令,構成了一個迴圈,這個不斷迴圈的過程叫作CPU 的指令週期,下面我們會詳細講解這個概念。

詳解 a = 11 + 15 的執行過程


上面我們瞭解了基本的程式執行過程,接下來我們來看看如果用馮諾依曼模型執行a=11+15是一個怎樣的過程。

我們再 Review 下這個問題:程式設計師寫的程式a=11+15是字串,CPU 不能執行字串,只能執行指令。所以這裡需要用到一種特殊的程式——編譯器。編譯器的核心能力是翻譯,它把一種程式翻譯成另一種程式語言。

這裡,我們需要編譯器將程式設計師寫的程式翻譯成 CPU 認識的指令(指令我們認為是一種低階語言,我們平時書寫的是高階語言)。你可以先跟我完整地學完作業系統,再去深入瞭解編譯原理的內容。

下面我們來詳細闡述 a=11+15 的執行過程:

1.編譯器通過分析,發現 11 和 15 是資料,因此編譯好的程式啟動時,會在記憶體中開闢出一個專門的區域存這樣的常數,這個專門用來儲存常數的區域,就是資料段,如下圖所示:

11 被儲存到了地址 0x100;

15 被儲存到了地址 0x104;

2.編譯器將a=11+15轉換成了 4 條指令,程式啟動後,這些指令被匯入了一個專門用來儲存指令的區域,也就是正文段。如上圖所示,這 4 條指令被儲存到了 0x200-0x20c 的區域中:

0x200 位置的 load 指令將地址 0x100 中的資料 11 匯入暫存器 R0;

0x204 位置的 load 指令將地址 0x104 中的資料 15 匯入暫存器 R1;

0x208 位置的 add 指令將暫存器 R0 和 R1 中的值相加,存入暫存器 R2;

0x20c 位置的 store 指令將暫存器 R2 中的值存回資料區域中的 0x1108 位置。

3.具體執行的時候,PC 指標先指向 0x200 位置,然後依次執行這 4 條指令。

這裡還有幾個問題要說明一下:

變數 a 實際上是記憶體中的一個地址,a 是給程式設計師的助記符。

為什麼 0x200 中代表載入資料到暫存器的指令是 0x8c000100,我們會在下面詳細討論。

不知道細心的同學是否發現,在上面的例子中,我們每次操作 4 個地址,也就是 32 位,這是因為我們在用 32 位寬的 CPU 舉例。在 32 位寬的 CPU 中,指令也是 32 位的。但是資料可以小於 32 位,比如可以加和兩個 8 位的位元組。

關於資料段和正文段的內容,會在模組四程式和執行緒部分繼續講解。

指令

接下來我會帶你具體分析指令的執行過程。

在上面的例子中,load 指令將記憶體中的資料匯入暫存器,我們寫成了 16 進位制:0x8c000100,拆分成二進位制就是:

這裡大家還是看下圖,需要看一下才能明白。

最左邊的 6 位,叫作操作碼,英文是 OpCode,100011 代表 load 指令;

中間的 4 位 0000是暫存器的編號,這裡代表暫存器 R0;

後面的 22 位代表要讀取的地址,也就是 0x100。

所以我們是把操作碼、暫存器的編號、要讀取的地址合併到了一個 32 位的指令中。

我們再來看一條求加法運算的 add 指令,16 進製表示是 0x08048000,換算成二進位制就是:

最左邊的 6 位是指令編碼,代表指令 add;

緊接著的 4 位 0000 代表暫存器 R0;

然後再接著的 4 位 0001 代表暫存器 R1;

再接著的 4 位 0010 代表暫存器 R2;

最後剩下的 14 位沒有被使用。

構造指令的過程,叫作指令的編碼,通常由編譯器完成;解析指令的過程,叫作指令的解碼,由 CPU 完成。由此可見 CPU 內部有一個迴圈:

首先 CPU 通過 PC 指標讀取對應記憶體地址的指令,我們將這個步驟叫作 Fetch,就是獲取的意思。

CPU 對指令進行解碼,我們將這個部分叫作 Decode。

CPU 執行指令,我們將這個部分叫作 Execution。

CPU 將結果存回暫存器或者將暫存器存入記憶體,我們將這個步驟叫作 Store。

上面 4 個步驟,我們叫作 CPU 的指令週期。CPU 的工作就是一個週期接著一個週期,周而復始。

指令的型別
通過上面的例子,你會發現不同型別(不同 OpCode)的指令、引數個數、每個引數的位寬,都不一樣。而引數可以是以下這三種型別:

暫存器;

記憶體地址;

數值(一般是整數和浮點)。

當然,無論是暫存器、記憶體地址還是數值,它們都是數字。

指令從功能角度來劃分,大概有以下 5 類:

I/O 型別的指令,比如處理和記憶體間資料交換的指令 store/load 等;再比如將一個記憶體地址的資料轉移到另一個記憶體地址的 mov 指令。

計算型別的指令,最多隻能處理兩個暫存器,比如加減乘除、位運算、比較大小等。

跳轉型別的指令,用處就是修改 PC 指標。比如程式設計中大家經常會遇到需要條件判斷+跳轉的邏輯,比如 if-else,swtich-case、函式呼叫等。

訊號型別的指令,比如傳送中斷的指令 trap。

閒置 CPU 的指令 nop,一般 CPU 都有這樣一條指令,執行後 CPU 會空轉一個週期。

指令還有一個分法,就是定址模式,比如同樣是求和指令,可能會有 2 個版本:

將兩個暫存器的值相加的 add 指令。

將一個暫存器和一個整數相加的 addi 指令。

另外,同樣是載入記憶體中的資料到暫存器的 load 指令也有不同的定址模式:

比如直接載入一個記憶體地址中的資料到暫存器的指令la,叫作直接定址。

直接將一個數值匯入暫存器的指令li,叫作暫存器定址。

將一個暫存器中的數值作為地址,然後再去載入這個地址中資料的指令lw,叫作間接定址。

因此定址模式是從指令如何獲取資料的角度,對指令的一種分類,目的是給編寫指令的人更多選擇。

瞭解了指令的型別後,我再強調幾個細節問題:

關於定址模式和所有的指令,只要你不是嵌入式開發人員,就不需要記憶,理解即可。

不同 CPU 的指令和暫存器名稱都不一樣,因此這些名稱也不需要你記憶。

有幾個暫存器在所有 CPU 里名字都一樣,比如 PC 指標、指令暫存器等。

指令的執行速度
之前我們提到過 CPU 是用石英晶體產生的脈衝轉化為時鐘訊號驅動的,每一次時鐘訊號高低電平的轉換就是一個週期,我們稱為時鐘週期。CPU 的主頻,說的就是時鐘訊號的頻率。比如一個 1GHz 的 CPU,說的是時鐘訊號的頻率是 1G。

到這裡你可能會有疑問:是不是每個時鐘週期都可以執行一條指令?其實,不是的,多數指令不能在一個時鐘週期完成,通常需要 2 個、4 個、6 個時鐘週期。

總結

接下來我們來做一個總結。這節課我們深入討論了指令和指令的分類。接下來,我們來看一看在 02 課時中留下的問題:

64 位和 32 位比較有哪些優勢?

【解析】 其實,這個問題需要分類討論:

如果說的是 64 位寬 CPU,那麼有 2 個優勢:

優勢 1:64 位 CPU 可以執行更大數字的運算,這個優勢在普通應用上不明顯,但是對於數值計算較多的應用就非常明顯。

優勢 2:64 位 CPU 可以定址更大的記憶體空間

如果 32 位/64 位說的是程式,那麼說的是指令是 64 位還是 32 位的。32 位指令在 64 位機器上執行,困難不大,可以相容。 如果是 64 位指令,在 32 位機器上執行就困難了。因為 32 位指令在 64 位機器執行的時候,需要的是一套相容機制;但是 64 位指令在 32 位機器上執行,32 位的暫存器都存不下指令的引數。

作業系統也是一種程式,如果是 64 位作業系統,也就是作業系統中程式的指令都是 64 位指令,因此不能安裝在 32 位機器上。

思考題
最後再給你出一道思考題:CPU 中有沒有求對數的指令?如果沒有那麼程式如何去計算?


04 | 構造複雜的程式:將一個遞迴函式轉成非遞迴函式的通用方法
05 | 儲存器分級:L1 Cache 比記憶體和 SSD 快多少倍?
加餐 | 練習題詳解(一)
模組二: Linux 指令入門
06 | 目錄結構和檔案管理指令:rm / -rf 指令的作用是?
07 | 程式、重定向和管道指令:xargs 指令的作用是?
上次學習
08 | 使用者和許可權管理指令: 請簡述 Linux 許可權劃分的原則?
09 | Linux 中的網路指令:如何檢視一個域名有哪些 NS 記錄?
10 | 軟體的安裝: 編譯安裝和包管理器安裝有什麼優勢和劣勢?
11 | 高階技巧之日誌分析:利用 Linux 指令分析 Web 日誌
12 | 高階技巧之叢集部署:利用 Linux 指令同時在多臺機器部署程式
加餐 | 練習題詳解(二)
模組三:作業系統基礎知識
13 | 作業系統核心:Linux 核心和 Windows 核心有什麼區別?
14 | 使用者態和核心態:使用者態執行緒和核心態執行緒有什麼區別?
15 | 中斷和中斷向量:Java/js 等語言為什麼可以捕獲到鍵盤輸入?
16 | Win/Mac/Unix/Linux 的區別和聯絡:為什麼 Debian 漏洞排名第一還這麼多人用?
加餐 | 練習題詳解(三)
模組四: 程式和執行緒

17 | 程式和執行緒:程式的開銷比執行緒大在了哪裡?
18 | 鎖、訊號量和分散式鎖:如何控制同一時間只有 2 個執行緒執行?
19 | 樂觀鎖、區塊鏈:除了上鎖還有哪些併發控制方法?
20 | 程式的排程:程式排程都有哪些方法?
21 | 哲學家就餐問題:什麼情況下會觸發飢餓和死鎖?
22 | 程式間通訊: 程式間通訊都有哪些方法?
23 | 分析服務的特性:我的服務應該開多少個程式、多少個執行緒?
加餐 | 練習題詳解(四)
模組五:記憶體管理

24 | 虛擬記憶體 :一個程式最多能使用多少記憶體?
25 | 記憶體管理單元: 什麼情況下使用大記憶體分頁?
26 | 快取置換演算法: LRU 用什麼資料結構實現更合理?
27 | 記憶體回收上篇:如何解決記憶體的迴圈引用問題?
28 | 記憶體回收下篇:三色標記-清除演算法是怎麼回事?
加餐 | 練習題詳解(五)
模組六:檔案系統

29 | Linux 下的各個目錄有什麼作用?
30 | 檔案系統的底層實現:FAT、NTFS 和 Ext3 有什麼區別?
待更新
31 | 資料庫檔案系統例項:MySQL 中 B 樹和 B+ 樹有什麼區別?
待更新
32 | HDFS 介紹:分散式檔案系統是怎麼回事?
待更新
加餐 | 練習題詳解(六)
待更新
模組七: 網路與安全
33 | 網際網路協議群(TCP/IP):多路複用是怎麼回事?
待更新
34 | UDP 協議:UDP 和 TCP 相比快在哪裡?
待更新
35 | Linux 的 I/O 模式:select/poll/epoll 有什麼區別?
待更新
36 | 公私鑰體系和網路安全:什麼是中間人攻擊?
待更新
加餐 | 練習題詳解(七)
待更新
模組八:虛擬化和其他
37 | 虛擬化技術介紹:VMware 和 Docker 的區別?
待更新
38 | 容器編排技術:如何利用 K8s 和 Docker Swarm 管理微服務?
待更新
39 | Linux 架構優秀在哪裡?
待更新
40 | 商業作業系統:電商作業系統是不是一個噱頭?
待更新
加餐 | 練習題詳解(八)

相關文章