1. 程式人生 > 實用技巧 >面試知識點整理之作業系統篇

面試知識點整理之作業系統篇

使用者態和核心態

現在作業系統都是採用虛擬儲存器,那麼對32位作業系統而言,它的定址空間(虛擬儲存空間)為4G(2的32次方)。作業系統的核心是核心,獨立於普通的應用程式,可以訪問受保護的記憶體空間,也有訪問底層硬體裝置的所有許可權。為了保證使用者程序不能直接操作核心(kernel),保證核心的安全,操心繫統將虛擬空間劃分為兩部分,一部分為核心空間,一部分為使用者空間。針對linux作業系統而言,將最高的1G位元組(從虛擬地址0xC00000000xFFFFFFFF),供核心使用,稱為核心空間,而將較低的3G位元組(從虛擬地址0x000000000xBFFFFFFF),供各個程序使用,稱為使用者空間。

在使用者態下,CPU只能訪問使用者空間記憶體;當在核心態時,CPU

既可以訪問使用者空間也可以訪問核心空間。

堆和棧的區別

  • 棧由系統編譯器管理,堆需要手動管理,及時釋放
  • 棧地址從高向低擴充套件,是連續的;堆地址從低向高擴充套件,是不連續的

程序和執行緒的區別

兩個名詞不過是對應的CPU時間段的描述:

程序就是包換上下文切換的程式執行時間總和 = CPU載入上下文+CPU執行+CPU儲存上下文。而執行緒是共享了程序的上下文環境,的更為細小的CPU時間段

  1. 程序是系統進行資源排程和分配的獨立單位,具有獨立的地址空間(也稱為段)。從上而下包括,棧,堆,未初始化變數區(BSS),初始化變數區(資料段),以及程式碼段。
  2. 執行緒間的資料通訊更為簡單
  3. 建立執行緒的速度要快於建立程序
  4. 程序的隔離性更好,一個執行緒的問題可能會影響同一程序內的所有執行緒
  5. 每個執行緒都在徵用程序中有限的虛擬地址空間,而程序可以使用全部有效虛擬記憶體
  6. 執行緒共享程序的虛擬地址空間(共享段、資料段)、使用者ID和組ID、檔案描述符表、當前工作目錄、但是執行緒也擁有屬於自己的棧,用來裝載本地變數和函式呼叫連結資訊。

執行緒同步

執行緒可以使用下面兩個工具來同步彼此行為:

  • 互斥量:保證資源不會被多個執行緒同時訪問

  • 條件變數:通知操作的方式保持多執行緒同步

並且條件變數總是與互斥量相關。

程序間通訊

程序間通訊IPC (InterProcess Communication)

工具包括匿名管道,命名管道,訊息佇列,訊號,共享記憶體,訊號量,socket

  • 管道是一種半雙工的通訊方式,資料只能單向流動,並且只能在具有親緣關係的程序間流動,程序的親緣關係通常是父子程序

  • 命名管道也是半雙工的通訊方式,但它允許無親緣關係的程序間進行通訊

  • 訊號可以在任何時候發給某一程序,而無需知道該程序的狀態,是軟體層次上對終端機制的模擬。常用的有

    • SIGHUP:使用者從終端登出,所有已啟動程序都將收到該訊號。系統預設狀態下對該訊號的處理是終止程序。
    • SIGINT:程式終止訊號。程式執行過程中,按Ctrl+C鍵將產生該訊號。
    • SIGQUIT:程式退出訊號。
    • SIGBUS和SIGSEGV:程序訪問非法地址。
    • SIGFPE:運算中出現致命錯誤,如除零操作、資料溢位等。
    • SIGKILL:使用者終止程序執行訊號。shell下執行kill -9傳送該訊號。
    • SIGTERM:結束程序訊號。shell下執行kill 程序pid傳送該訊號。
    • SIGALRM定時器訊號。
    • SIGCLD:子程序退出訊號。如果其父程序沒有忽略該訊號也沒有處理該訊號,則子程序退出後將形成殭屍程序。
  • 訊息佇列是訊息的連結串列,存放在核心中並由訊息佇列識別符號標識,與管道不同的還有,訊息佇列在某個程序往一個佇列寫入訊息之前,並不需要另外某個程序在該佇列上等待訊息的到達。但是它們都是先進先出的。

  • 共享記憶體是核心專門留出了一塊記憶體區,可以由需要訪問的程序將其對映到自己的私有地址空間。多個程序可以可以直接讀寫同一塊記憶體空間,是最快的可用IPC形式。當某程序改變了共享記憶體的內容,其他所有程序會立即瞭解到這一變化。

  • 訊號量是一個計數器,用於多程序對共享資料的訪問,訊號量的意圖在於程序間同步。

    訊號量與互斥量之間的區別:
    (1)互斥量用於執行緒的互斥,訊號量用於執行緒的同步。
    互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。
    同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。
    (2)互斥量值只能為0/1,訊號量值可以為非負整數。一個互斥量只能用於一個資源的互斥訪問,它不能實現多個資源的多執行緒互斥問題。訊號量可以實現多個同類資源的多執行緒互斥和同步。當訊號量為單值訊號量時,也可以完成一個資源的互斥訪問。
    (3)互斥量的加鎖和解鎖必須由同一執行緒分別對應使用,訊號量可以由一個執行緒釋放,另一個執行緒得到。

  • socket:可以讓不在同一臺計算機但通過網路連線計算機上的程序進行通訊。

訊號量和檔案鎖可以用於同步。互斥量和條件變數通常用於執行緒同步。

程序的狀態

  • 就緒狀態,等待CPU。也可以細分為活躍就緒(程序在主存中可以被排程)和靜止就緒(程序被對換到輔存時,不能被排程)。
  • 執行狀態,已獲得CPU
  • 阻塞狀態,例如請求I/O,申請緩衝空間。與就緒類似的也可以細分為活躍阻塞和靜止阻塞。

此外還有:

  • 建立狀態:程序還在被建立,尚未到就緒狀態
  • 結束狀態

什麼是死鎖,如何解決

產生死鎖的條件有四個:

  1. 互斥條件:所謂互斥就是程序在某一時間內獨佔資源。
  2. 請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放
  3. 不剝奪條件:程序已獲得資源,在末使用完之前,不能強行剝奪。
  4. 迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。

死鎖預防:破壞任意一個必要條件就可以預防死鎖。例如,以一定順序獲得鎖,或者一次申請全部的資源,以及超時放棄鎖。

死鎖避免:每次申請資源時判斷操作是否安全。[銀行家演算法]([http://chuxiuhong.com/2016/11/26/1 (5)/](http://chuxiuhong.com/2016/11/26/1 (5)/)

死鎖檢測:判斷系統是否處於死鎖狀態。資源分配圖。

死鎖解除:

  • 剝奪,將某程序資源強行收回,分配給其他程序。
  • 撤銷程序

分頁和分段

程序地址空間與虛擬儲存空間的理解

段和頁用來解決:

  1. 程序地址空間不隔離
  2. 記憶體使用效率低
  3. 程式執行地址不確定

因此增加了一箇中間層,使用虛擬地址對映到實體地址的方式進行訪問。這樣對於程式來說,只需要關注虛擬地址。即使虛擬地址一樣,對於不同的程序來說,仍然可以保證不同程式最終訪問記憶體地址位於不同區域,用以解決1和3的問題。此時,引入分段的思想,在虛擬地址空間和實體地址空間做一一對映。

而分頁用以解決每次換入記憶體過大的問題2,即用更小粒度的記憶體分隔和對映方法。當CPU訪問程式中用到的虛擬地址時,發現沒有對應的實體地址,會引發一個頁錯誤。此時由作業系統建立對映,並由CPU重新執行。因此,隨著程式執行,頁錯誤會不斷產生,作業系統也會分配相應的物理頁來滿足執行需求。

另外,當記憶體不足發生頁錯誤時(缺頁中斷),作業系統會在記憶體選擇一個頁面移出記憶體,稱為頁面置換演算法。

虛擬記憶體將主存看成是一個磁碟的快取記憶體,主存中只儲存活動區域,並根據需要在磁碟和主存之間來回傳送資料。

什麼是記憶體(二):虛擬記憶體

分頁與分段管理的比較:

  • 頁是資訊的物理單位,分頁是為實現離散分配方式,以消減記憶體的外零頭,提高記憶體的利用率。段則是資訊的邏輯單位,它含有一組其意義相對完整的資訊。分段的目的是為了能更好地滿足使用者的需要。
  • 頁的大小固定且由系統決定;而段的長度卻不固定,決定於使用者所編寫的程式。
  • 分頁的地址空間是一維的,程式設計師只需利用一個記憶符,即可表示一個地址;而分段的作業地址空間是二維的,程式設計師在標識一個地址時,既需給出段名,又需給出段內地址。

頁面置換演算法

  • 最佳置換演算法(理想情況下):有些頁面在記憶體中,知道其中有一頁將很快被訪問,其他頁面會在執行10、100或者1000條指令才會被訪問,那麼將1000條指令的頁面(最大標記數)置換出去。雖然不可實現,可以用來對演算法進行衡量。
  • 先進先出置換演算法:選擇在主存中停留時間最長的頁置換出去
  • 最近最久未使用(LRU)演算法:選擇最近一段時間裡沒有使用過的頁面予以置換
  • clock演算法
  • 最少使用(LFU)演算法:選擇近期最少使用的頁面淘汰
  • 最近未使用(NRU)演算法
  • 二次機會演算法:每個頁面擁有2次機會才會被淘汰出去
  • ...

排程策略

  • 先來先排程
  • 短作業先排程
  • 高優先權先排程,又分為搶佔式和非搶佔式
  • 高響應比優先排程,即根據響應時間/要求服務時間的比重,隨著等待時間增加,優先順序提高
  • 時間片輪轉,可以在給定時間內響應所有使用者請求
  • 多級反饋佇列,新任務放置在1的隊尾,如果未完成,轉移到2的隊尾,

殭屍程序和孤兒程序

某一子程序的父程序終止後,該程序變成孤兒程序,由init接管。

而在父程序執行wait()之前,子程序就終止了,那麼子程序將成為殭屍程序。它仍然儲存著核心程序表中的記錄,包含子程序ID、終止狀態、資源使用資料等資訊,等待著父程序呼叫wait()後,核心將其刪除。

記憶體分配

  • 單一連續分配:適合單使用者單任務系統
  • 固定分割槽分配:大程式無法放置分割槽中,小程式容易產生碎片
  • 動態分割槽分配:
    • 首次適應:從低地址開始查詢
    • 最佳適應:空閒分割槽從小到大排列,找到第一個能滿足要求的分割槽
    • 最壞適應:空閒分割槽從大到小排列,挑選最大分割槽
    • 迴圈首次適應:從上次查詢結束的位置開始查詢
    • 快速適應:對空閒分割槽按照大小進行分類,對每一類空閒分割槽單獨設定連結串列