操作系統面試題(必考)

2020-08-10 11:40:35

什麼是進程?

進程就是正在執行的程式,是操作系統資源分配的基本單位。一般來說,進程包含指令、數據和PCB。

延伸問題:孤兒進程和殭屍進程有什麼區別?

  • 孤兒進程就是說一個父進程退出,而它的一個或多個子進程還在執行,那麼這些子進程將成爲孤兒進程。孤兒進程將被 init 進程(進程ID爲1的進程)所收養,並由 init 進程對它們完成狀態收集工作。因爲孤兒進程會被 init 進程收養,所以孤兒進程不會對系統造成危害。
  • 殭屍進程就是一個子進程的進程描述符在子進程退出時不會釋放,只有當父進程通過 wait() 或 waitpid() 獲取了子進程資訊後纔會釋放。如果子進程退出,而父進程並沒有呼叫 wait() 或 waitpid(),那麼子進程的進程描述符仍然儲存在系統中,這種進程稱之爲殭屍進程。殭屍進程通過 ps 命令顯示出來的狀態爲 Z。

系統所能使用的進程號是有限的,如果產生大量殭屍進程,可能會因爲沒有可用的進程號而導致系統不能產生新的進程。如果要消滅系統中大量的殭屍進程,只需要將其父進程殺死,此時殭屍進程就會變成孤兒進程,從而被 init 進程所收養,這樣 init 進程就會釋放所有的殭屍進程所佔有的資源,從而結束殭屍進程。

延伸問題:什麼是守護行程?

守護行程是執行在後台的一種特殊進程,它是獨立於控制終端的,並週期性地執行某些任務。

什麼是執行緒?

執行緒是進程內部的不同的執行路徑,是操作系統獨立排程的基本單位。一個進程中可以有多個執行緒,它們共用進程資源。比如說,微信和瀏覽器是兩個進程,瀏覽器進程裏面有很多執行緒,例如 HTTP 請求執行緒、事件響應執行緒、渲染執行緒等等,執行緒的併發執行使得在瀏覽器中點選一個新鏈接從而發起 HTTP 請求時,瀏覽器還可以響應使用者的其它事件。

進程與執行緒有什麼區別?

擁有資源

進程是資源分配的基本單位,但是執行緒不擁有資源,執行緒可以存取隸屬於進程的資源。

排程

執行緒是獨立排程的基本單位,在同一進程中,執行緒的切換不會引起進程切換,從一個進程中的執行緒切換到另一個進程中的執行緒時,會引起進程切換。

系統開銷

由於建立或復原進程時,系統都要爲之分配或回收資源,如記憶體空間、I/O 裝置等,所付出的開銷遠大於建立或復原執行緒時的開銷。類似地,在進行進程切換時,涉及當前執行進程 CPU 環境的儲存及新排程進程 CPU 環境的設定,而執行緒切換時只需儲存和設定少量暫存器內容,開銷很小。

通訊方面

執行緒間可以通過直接讀寫同一進程中的數據進行通訊,但是進程通訊需要藉助 IPC。

延伸問題:執行緒有哪兩種?

  • 使用者級執行緒(user level thread):對於這類執行緒,有關執行緒管理的所有工作都由應用程式完成,內核意識不到執行緒的存在。在應用程式啓動後,操作系統分配給該程式一個進程號,以及其對應的記憶體空間等資源。應用程式通常先在一個執行緒中執行,該執行緒被成爲主執行緒。在其執行的某個時刻,可以通過呼叫執行緒庫中的函數建立一個在相同進程中執行的新執行緒。使用者級執行緒的好處是非常高效,不需要進入內核空間,但併發效率不高。
  • 內核級執行緒(kernel level thread):對於這類執行緒,有關執行緒管理的所有工作由內核完成,應用程式沒有進行執行緒管理的程式碼,只能呼叫內核執行緒的介面。內核維護進程及其內部的每個執行緒,排程也由內核基於執行緒架構完成。內核級執行緒的好處是,內核可以將不同線程更好地分配到不同的CPU,以實現真正的並行計算。

事實上,在現代操作系統中,往往使用組合方式實現多執行緒,即執行緒建立完全在使用者空間中完成,並且一個應用程式中的多個使用者級執行緒被對映到一些內核級執行緒上,相當於是一種折中方案。

併發和並行有什麼區別?

併發就是在一段時間內,多個任務都會被處理;但在某一時刻,只有一個任務在執行。單核處理器可以做到併發。比如有兩個進程A和B,A執行一個時間片之後,切換到B,B執行一個時間片之後又切換到A。因爲切換速度足夠快,所以宏觀上表現爲在一段時間內能同時執行多個程式。

並行就是在同一時刻,有多個任務在執行。這個需要多核處理器才能 纔能完成,在微觀上就能同時執行多條指令,不同的程式被放到不同的處理器上執行,這個是物理上的多個進程同時進行。

大內核和微內核有什麼區別?

  • 大內核,就是將操作系統的全部功能都放進內核裏面,包括排程、檔案系統、網路、裝置驅動器、儲存管理等等,組成一個緊密連線整體。大內核的優點就是效率高,但是很難定位bug,拓展性比較差,每次需要增加新的功能,都要將新的程式碼和原來的內核程式碼重新編譯。
  • 微內核與單體內核不同,微內核只是將操作中最核心的功能加入內核,包括IPC、地址空間分配和基本的排程,這些東西都在內核態執行,其他功能作爲模組被內核呼叫,並且是在使用者空間執行。微內核比較好維護和拓展,但是效率可能不高,因爲需要頻繁地在內核態和使用者態之間切換。

分時系統和實時系統有什麼區別?

  • 分時系統(Sharing time system)就是系統把CPU時間分成很短的時間片,輪流地分配給多個作業。它的優點就是對多個使用者的多個作業都能保證足夠快的響應時間,並且有效提高了資源的利用率。
  • 實時系統(Real-time system)是系統對外部輸入的資訊,能夠在規定的時間內(截止期限)處理完畢並做出反應。它的優點是能夠集中地及時地處理並作出反應,高可靠性,安全性。
  • 通常計算機採用的是分時,就是多個進程/使用者之間共用CPU,從形勢上實現多工。各個使用者/進程之間的排程並非精準度特別高,如果一個進程被鎖住,可以給它分配更多的時間。而實時操作系統則不同,軟體和硬體必須遵從嚴格的時間限制,超過時限的進程可能直接被終止。在這樣的操作系統中,每次加鎖都需要仔細考慮。

靜態鏈接和動態鏈接有什麼區別?

  • 靜態鏈接就是在編譯期間,由編譯器和聯結器將靜態庫整合到應用程式內,並製作成目標檔案以及可以獨立運作的可執行檔案。靜態庫一般是一些外部函數與變數的集合。
  • 靜態庫很方便,但是如果我們只是想用庫中的某一個函數,卻仍然得把所有的內容都鏈接進去。一個更現代的方法是使用共用庫,避免了在檔案中靜態庫的大量重複。
  • 動態鏈接可以在首次載入的時候執行,也可以在程式開始執行的時候完成。這個是由動態鏈接器完成,比方標準 C 庫(libc.so) 通常就是動態鏈接的,這樣所有的程式可以共用同一個庫,而不用分別進行封裝。

編譯有哪些階段?

  • 預處理階段:處理以 # 開頭的預處理命令;
  • 編譯階段:翻譯成彙編檔案;
  • 彙編階段:將彙編檔案翻譯成可重定位目標檔案;
  • 鏈接階段:將可重定位目標檔案和 printf.o 等單獨預編譯好的目標檔案進行合併,得到最終的可執行目標檔案。

進程有哪些狀態?

 

  • 在五狀態模型裏面,進程一共有5中狀態,分別是建立、就緒、執行、終止、阻塞。
  • 執行狀態就是進程正在CPU上執行。在單處理機環境下,每一時刻最多隻有一個進程處於執行狀態。
  • 就緒狀態就是說進程已處於準備執行的狀態,即進程獲得了除CPU之外的一切所需資源,一旦得到CPU即可執行。
  • 阻塞狀態就是進程正在等待某一事件而暫停執行,比如等待某資源爲可用或等待I/O完成。即使CPU空閒,該進程也不能執行。

執行態→阻塞態:往往是由於等待外設,等待主記憶體等資源分配或等待人工幹預而引起的。

阻塞態→就緒態:則是等待的條件已滿足,只需分配到處理器後就能執行。

執行態→就緒態:不是由於自身原因,而是由外界原因使執行狀態的進程讓出處理器,這時候就變成就緒態。例如時間片用完,或有更高優先順序的進程來搶佔處理器等。

就緒態→執行態:系統按某種策略選中就緒佇列中的一個進程佔用處理器,此時就變成了執行態。

進程排程演算法有哪些?

先來先服務

非搶佔式的排程演算法,按照請求的順序進行排程。

有利於長作業,但不利於短作業,因爲短作業必須一直等待前面的長作業執行完畢才能 纔能執行,而長作業又需要執行很長時間,造成了短作業等待時間過長。另外,對I/O密集型進程也不利,因爲這種進程每次進行I/O操作之後又得重新排隊。

短作業優先

非搶佔式的排程演算法,按估計執行時間最短的順序進行排程。

長作業有可能會餓死,處於一直等待短作業執行完畢的狀態。因爲如果一直有短作業到來,那麼長作業永遠得不到排程。

最短剩餘時間優先

最短作業優先的搶佔式版本,按剩餘執行時間的順序進行排程。 當一個新的作業到達時,其整個執行時間與當前進程的剩餘時間作比較。如果新的進程需要的時間更少,則掛起當前進程,執行新的進程。否則新的進程等待。

時間片輪轉

將所有就緒進程按 FCFS 的原則排成一個佇列,每次排程時,把 CPU 時間分配給隊首進程,該進程可以執行一個時間片。當時間片用完時,由計時器發出時鐘中斷,排程程式便停止該進程的執行,並將它送往就緒佇列的末尾,同時繼續把 CPU 時間分配給隊首的進程。

時間片輪轉演算法的效率和時間片的大小有很大關係:

  • 因爲進程切換都要儲存進程的資訊並且載入新進程的資訊,如果時間片太小,會導致進程切換得太頻繁,在進程切換上就會花過多時間。
  • 而如果時間片過長,那麼實時性就不能得到保證。

優先順序排程

爲每個進程分配一個優先順序,按優先順序進行排程。

爲了防止低優先順序的進程永遠等不到排程,可以隨着時間的推移增加等待進程的優先順序。

延伸問題:什麼是搶佔式排程?什麼是非搶佔式排程?

  • 搶佔式就是說操作系統將正在執行的進程強行暫停,由排程器將CPU分配給其他就緒進程。

  • 非搶佔式是排程器一旦把處理機分配給某進程後便讓它一直執行下去,直到進程完成或發生進程排程進程排程某事件而阻塞時,才把處理機分配給另一個進程。

什麼是上下文切換?

對於單核單執行緒CPU而言,在某一時刻只能執行一條CPU指令。上下文切換(Context Switch)是一種將CPU資源從一個進程分配給另一個進程的機制 機製。從使用者角度看,計算機能夠並行執行多個進程,這恰恰是操作系統通過快速上下文切換造成的結果。在切換的過程中,操作系統需要先儲存當前進程的狀態(包括記憶體空間的指針,當前執行完的指令等等),再讀入下一個進程的狀態,然後執行此進程。

系統呼叫和庫函數有什麼區別?

  • 系統呼叫是應用程式向系統內核請求服務的方式。可以包括硬體相關的服務(例如,存取硬碟等),或者建立新進程,排程其他進程等。系統呼叫是程式和操作系統之間的重要介面。
  • 庫函數就是說把一些常用的函數編寫完放到一個檔案裡,編寫應用程式時呼叫,這是由第三方提供的,發生在使用者地址空間。
  • 在移植性方面,不同操作系統的系統呼叫一般是不同的,移植性差;庫函數會相對好一些。比如說在所有的ANSI C編譯器版本中,C庫函數是相同的。
  • 在呼叫開銷方面,系統呼叫需要在使用者空間和內核環境間切換,開銷較大;而庫函數呼叫開銷較小。

什麼是死鎖?

在兩個或多個併發進程中,如果一個進程集閤中的每個進程都在等待只能由該進程集閤中的其他進程才能 纔能引發的事件,那麼該進程集合就產生了死鎖。

延伸問題:死鎖產生有哪些條件?

死鎖產生的根本原因是多個進程競爭資源時,進程的推進順序出現不正確。

  • 互斥:每個資源要麼已經分配給了一個進程,要麼就是可用的。
  • 佔有和等待:已經得到了某個資源的進程可以再請求新的資源。
  • 不可搶佔:已經分配給一個進程的資源不能強制性地被搶佔,它只能被佔有它的進程顯式地釋放。
  • 環路等待:有兩個或者兩個以上的行程羣組成一條環路,該環路中的每個進程都在等待下一個進程所佔有的資源。

延伸問題:怎麼解決死鎖?

對於死鎖,主要有4種解決策略。

鴕鳥策略

就是直接忽略死鎖。就像鴕鳥遇到危險的時候,把頭埋在沙子裡,假裝根本沒發生問題。因爲解決死鎖問題的代價很高,因此鴕鳥策略這種不採取任務措施的方案會獲得更高的效能。當發生死鎖時不會對使用者造成多大影響,或發生死鎖的概率很低,可以採用鴕鳥策略。大多數操作系統,包括 Unix,Linux 和 Windows,處理死鎖問題的辦法僅僅是忽略它。

死鎖預防

死鎖預防是指通過破壞死鎖產生的四個必要條件中的一個或多個,以避免發生死鎖。

  • 破壞互斥:不讓資源被一個進程獨佔,可通過假離線技術允許多個進程同時存取資源;
  • 破壞佔有和等待:有兩種方案,
    • 已擁有資源的進程不能再去請求其他資源。一種實現方法是要求進程在開始執行前請求需要的所有資源。
    • 要求進程請求資源時,先暫時釋放其當前擁有的所有資源,再嘗試一次獲取所需的全部資源。
  • 破壞不可搶佔:有些資源可以通過虛擬化方式實現可搶佔;
  • 破壞回圈等待:有兩種方案:
    • 一種方法是保證每個進程在任何時刻只能佔用一個資源,如果要請求另一個資源,必須先釋放第一個資源;
    • 另一種方法是將所有資源進行統一編號,進程可以在任何時刻請求資源,但要求進程必須按照順序請求資源。

死鎖避免

爲了避免因爲預防死鎖而導致所有執行緒變慢,死鎖避免採用了與死鎖預防相反的措施。它允許三個必要條件,但通過演算法判斷資源請求是否可能導致回圈等待的形成並相應決策,來避免死鎖點的產生。因此,其前提是知道當前資源使用的整體情況,以及申請資源執行緒本身所佔有的資源細節。

判斷和決策中,主要使用兩種避免方法。

  • 執行緒啓動拒絕:如果一個執行緒的請求會引發死鎖,則不允許其啓動。
  • 資源分配拒絕:如果一個執行緒增加的資源請求會導致死鎖,則不允許此申請。

整體來看,死鎖避免是從資源和執行緒相互間關係着手,避免形成回圈等待是其主要任務。

死鎖檢測和恢復

可以允許系統進入死鎖狀態,但會維護一個系統的資源分配圖,定期呼叫死鎖檢測演算法來檢測途中是否存在死鎖,檢測到死鎖發生後,採取死鎖恢復演算法進行恢復。

死鎖檢測方法如下:

  • 在資源分配圖中,找到不會阻塞又不獨立的進程結點,使該進程獲得其所需資源並執行,執行完畢後,再釋放其所佔有的全部資源。也就是消去該進程結點的請求邊和分配邊。
  • 使用上面的演算法進行一系列簡化,若能消去所有邊,則表示不會出現死鎖,否則會出現死鎖。

檢測到死鎖後,就需要解決死鎖。目前操作系統中主要採用如下幾種方法:

  • 取消所有死鎖相關執行緒,簡單粗暴,但也確實是最常用的
  • 把每個死鎖執行緒回滾到某些檢查點,然後重新啓動
  • 連續取消死鎖執行緒直到死鎖解除,順序基於特定最小代價原則
  • 連續搶佔資源直到死鎖解除

進程同步的方式有哪些?

臨界區

臨界區是一段程式碼,在臨界區內進程將存取臨界資源。任何時候最多隻有一個進程可以進入臨界區,也就是說,臨界區具有排他性。所以,爲了互斥存取臨界資源,每個進程在進入臨界區之前,需要先進行檢查。

互斥量

就是使用一個互斥的變數來直接制約多個進程,每個進程只有擁有這個變數才具有存取公共資源的許可權,因爲互斥量只有一個,所以能保證資源的正確存取。

號志

號志(Semaphore)是一個整型變數,可以對其執行自增和自減操作,自減操作通常也叫做P操作,自增操作也稱爲V操作。這兩個操作需要被設計成原語,是不可分割,通常的做法是在執行這些操作的時候遮蔽中斷。進程使用這兩個操作進行同步。

  • 對於P操作,如果執行操作後號志小於 0,那麼執行該操作的進程就會阻塞,否則繼續執行;
  • 對於V操作,如果操作之後的號志小於等於0,那麼就會從阻塞佇列喚醒一個進程。

管程

管程使用的是物件導向思想,將表示共用資源的數據結構還有相關的操作,包括同步機制 機製,都集中並封裝到一起。所有進程都只能通過管程間接存取臨界資源,而管程只允許一個進程進入並執行操作,從而實現進程互斥。管程中設定了多個條件變數,表示多個進程被阻塞或掛起的條件。對條件變數執行 wait() 操作會導致呼叫進程阻塞,把管程讓出來給另一個進程持有。signal() 操作用於喚醒被阻塞的進程。管程有一個重要特性,就是在一個時刻只能有一個進程使用管程。進程在無法繼續執行的時候不能一直佔用管程,否則其它進程永遠不能使用管程。

進程間通訊的方式有哪些?

管道

  • 管道是半雙工的,數據只能向一個方向流動;如果需要雙方通訊時,需要建立起兩個管道。
  • 管道只能用於父子進程或者兄弟進程之間或者說具有親緣關係的進程;
  • 管道對於管道兩端的進程而言,就是一個檔案,但它不是普通的檔案,它不屬於某種檔案系統,只存在與記憶體中。
  • 管道的實質是一個內核緩衝區,進程以先進先出的方式從緩衝區存取數據,管道一端的進程順序的將數據寫入緩衝區,另一端的進程則順序的讀出數據。該緩衝區可以看做是一個回圈佇列,讀和寫的位置都是自動增長的,不能隨意改變,一個數據只能被讀一次,讀出來以後在緩衝區就不復存在了。當緩衝區讀空或者寫滿時,有一定的規則控制相應的讀進程或者寫進程進入等待佇列,當空的緩衝區有新數據寫入或者滿的緩衝區有數據讀出來時,就喚醒等待佇列中的進程繼續讀寫。
  • 管道的主要侷限性正體現在它的特點上,比如只支援單向數據流,只能用於具有親緣關係的進程之間,沒有名字,管道的緩衝區是有限的等等。

命名管道

這種管道也叫FIFO。命名管道不同於管道的地方,在於它提供了一個路徑名與之關聯,以命名管道的檔案形式存在於檔案系統中,這樣,即使與命名管道的建立進程不存在親緣關係的進程,只要可以存取檔案系統中的這個路徑,就能夠彼此通過命名管道相互通訊。命名管道嚴格遵循先進先出原則的,不支援諸如數據隨機定位。命名管道的名字存在於檔案系統中,但內容存放在記憶體中。

訊息佇列

訊息佇列是訊息的鏈表,具有特定的格式,它是存放在記憶體裏面的,並且每個訊息佇列都有唯一的標識。訊息佇列允許一個或多個進程向它寫入與讀取訊息,所以,利用訊息佇列,一個進程可以將一個數據塊發送到另一個進程,每個數據塊都有一個型別,接收進程可以獨立地接收含有不同類型的數據結構,這個過程是非同步的,我們可以通過發送訊息來避免命名管道的同步和阻塞問題。但訊息佇列的數據塊有一個最大長度的大小限制。

共用記憶體

  • 共用記憶體是針對其他通訊機制 機製執行效率較低而設計的,它可以讓多個進程可以可以直接讀寫同一塊記憶體空間,是最快的IPC形式。
  • 爲了在多個進程間交換資訊,內核專門留出了一塊記憶體區,可以由需要存取的進程將其對映到自己的私有地址空間。進程就可以直接讀寫這一塊記憶體而不需要進行數據的拷貝,從而大大提高效率。
  • 由於多個進程共用一段記憶體,因此需要依靠某種同步機制 機製來達到進程間的同步和互斥。

號志

號志是一個計數器,可以用來控制多個進程對共用資源的存取。它是一種類似於鎖的機制 機製,就是防止某進程正在存取共用資源時,其他進程也存取該資源。參考這裏

Socket

  • Socket就是通訊端,通訊端也是一種通訊機制 機製,憑藉這種機制 機製,可以讓不在同一臺主機上的兩個進程,通過網路進行通訊,一般可以用在用戶端和伺服器之間的通訊。
  • 實際上,Socket 是在應用層和傳輸層之間的一個抽象層,它把 TCP/IP 協定的傳輸層裏面複雜的操作,抽象爲幾個簡單的介面,供應用層呼叫實現進程在網路中的通訊。

延伸問題:Socket通訊流程是怎樣的?

 

  • 概括地說,就是通訊的兩端都建立了一個 Socket ,然後通過 Socket 對數據進行傳輸。通常伺服器處於一個無限回圈,等待用戶端的連線。
  • 對於用戶端,它的的過程比較簡單,首先建立 Socket,通過TCP連線伺服器,將 Socket 與遠端主機的某個進程連線,然後就發送數據,或者讀取響應數據,直到數據交換完畢,關閉連線,結束 TCP 對話。
  • 對於伺服器端,先初始化 Socket,建立流式通訊端,與本機地址及埠進行系結,然後通知 TCP,準備好接收連線,呼叫 accept() 阻塞,等待來自用戶端的連線。如果這時用戶端與伺服器建立了連線,用戶端發送數據請求,伺服器接收請求並處理請求,然後把響應數據發送給用戶端,用戶端讀取數據,直到數據交換完畢。最後關閉連線,互動結束。

延伸問題:從TCP連線的角度說說Socket通訊流程。

 

首先是三次握手的Socket互動流程。

  1. 伺服器呼叫 socket()、bind()、listen() 完成初始化後,呼叫 accept() 阻塞等待;
  2. 用戶端 Socket 物件呼叫 connect() 向伺服器發送了一個 SYN 並阻塞;
  3. 伺服器完成了第一次握手,即發送 SYN 和 ACK 應答;
  4. 用戶端收到伺服器端發送的應答之後,從 connect() 返回,再發送一個 ACK 給伺服器;
  5. 伺服器 Socket 物件接收用戶端第三次握手 ACK 確認,此時伺服器端從 accept() 返回,建立連線。

接下來就是兩個端的連線物件互相收發數據。

 

然後是四次揮手的Socket互動流程。

  1. 某個應用進程呼叫 close() 主動關閉,發送一個 FIN;
  2. 另一端接收到 FIN 後被動執行關閉,併發送 ACK 確認;
  3. 之後被動執行關閉的應用進程呼叫 close() 關閉 Socket,並也發送一個 FIN;
  4. 接收到這個 FIN 的一端向另一端 ACK 確認。

有哪些磁碟排程演算法?

先來先服務

  • 按照磁碟請求的順序進行排程。
  • 優點是公平和簡單。缺點也很明顯,因爲未對尋道做任何優化,使平均尋道時間可能較長。

最短尋道時間優先

  • 優先排程與當前磁頭所在磁軌距離最近的磁軌。
  • 雖然平均尋道時間比較低,但是不夠公平。如果新到達的磁軌請求總是比一個在等待的磁軌請求近,那麼在等待的磁軌請求會一直等待下去,也就是出現飢餓現象。一般來說,兩端的磁軌請求更容易出現飢餓現象。

電梯演算法

  • 也叫SCAN掃描演算法。電梯演算法就是說讀寫磁頭總是保持一個方向執行,直到該方向沒有請求爲止,然後改變執行方向。
  • 因爲考慮了移動方向,因此所有的磁碟請求都會被滿足,解決了最短尋道時間優先的飢餓問題。

什麼是虛擬記憶體?

虛擬記憶體就是說,讓實體記憶體擴充成更大的邏輯記憶體,從而讓程式獲得更多的可用記憶體。虛擬記憶體使用部分載入的技術,讓一個進程或者資源的某些頁面載入進記憶體,從而能夠載入更多的進程,甚至能載入比記憶體大的進程,這樣看起來好像記憶體變大了,這部分記憶體其實包含了磁碟或者硬碟,並且就叫做虛擬記憶體。

什麼是分頁系統?

分頁就是說,將磁碟或者硬碟分爲大小固定的數據塊,叫做頁,然後記憶體也分爲同樣大小的塊,叫做頁框。當進程執行的時候,會將磁碟的頁載入記憶體的某些頁框中,並且正在執行的進程如果發生缺頁中斷也會發生這個過程。頁和頁框都是由兩個部分組成的,一個是頁號或者頁框號,一個是偏移量。分頁一般是有硬體來完成的,每個頁都對應一個頁框,它們的對應關係存放在一個叫做頁表的數據結構中,頁號作爲這個頁表的索引,頁框號作爲頁表的值。操作系統負責維護這個頁表。

分頁和分段有什區別?

  • 分頁對程式設計師是透明的,但是分段需要程式設計師顯式劃分每個段。
  • 分頁的地址空間是一維地址空間,分段是二維的。
  • 頁的大小不可變,段的大小可以動態改變。
  • 分頁主要用於實現虛擬記憶體,從而獲得更大的地址空間;分段主要是爲了使程式和數據可以被劃分爲邏輯上獨立的地址空間並且有助於共用和保護。

頁面替換演算法有哪些?

在程式執行過程中,如果要存取的頁面不在記憶體中,就發生缺頁中斷從而將該頁調入記憶體中。此時如果記憶體已無空閒空間,系統必須從記憶體中調出一個頁面到磁碟對換區中來騰出空間。

最佳演算法

所選擇的被換出的頁面將是最長時間內不再被存取,通常可以保證獲得最低的缺頁率。這是一種理論上的演算法,因爲無法知道一個頁面多長時間不再被存取。

先進先出

選擇換出的頁面是最先進入的頁面。該算***將那些經常被存取的頁面也被換出,從而使缺頁率升高。

LRU

雖然無法知道將來要使用的頁面情況,但是可以知道過去使用頁面的情況。LRU 將最近最久未使用的頁面換出。爲了實現 LRU,需要在記憶體中維護一個所有頁面的鏈表。當一個頁面被存取時,將這個頁面移到鏈表表頭。這樣就能保證鏈表表尾的頁面是最近最久未存取的。因爲每次存取都需要更新鏈表,因此這種方式實現的 LRU 代價很高。

時鐘演算法

時鐘演算法使用環形鏈表將頁面連線起來,再使用一個指針指向最老的頁面。它將整個環形鏈表的每一個頁面做一個標記,如果標記是0,那麼暫時就不會被替換,然後時鐘演算法遍歷整個環,遇到標記爲1的就替換,否則將標記爲0的標記爲1。

Linux檔案系統是怎麼樣的?

Linux檔案系統裏面有檔案和目錄,組成一個樹狀的結構,樹的每一個葉子節點表示檔案或者空目錄。每個檔案基本上都由兩部分組成:

  • inode:一個檔案佔用一個 inode,記錄檔案的屬性,同時記錄此檔案的內容所在的 block 編號;
  • block:記錄檔案的內容,檔案太大時,會佔用多個 block。

除此之外還包括:

  • superblock:記錄檔案系統的整體資訊,包括 inode 和 block 的總量、使用量、剩餘量,以及檔案系統的格式與相關資訊等;
  • block bitmap:記錄 block 是否被使用的點陣圖。

當要讀取一個檔案的內容時,先在 inode 中查詢檔案內容所在的所有 block,然後把所有 block 的內容讀出來。

 

硬鏈接和軟鏈接有什麼區別?

  • 硬鏈接就是在目錄下建立一個條目,記錄着檔名與 inode 編號,這個 inode 就是原始檔的 inode。刪除任意一個條目,檔案還是存在,只要參照數量不爲 0。但是硬鏈接有限制,它不能跨越檔案系統,也不能對目錄進行鏈接。
  • 符號鏈接檔案儲存着原始檔所在的絕對路徑,在讀取時會定位到原始檔上,可以理解爲 Windows 的快捷方式。當原始檔被刪除了,鏈接檔案就打不開了。因爲記錄的是路徑,所以可以爲目錄建立符號鏈接。