操作系統面試知識大盤點

前言

這篇文章南國根據自己的理解 寫一篇在互聯網公司面試中操作系統常問的知識點。本篇博客許多內容都是在前人的基礎上進行的總結和概括,所以這篇博客 南國還是那他歸納爲轉載。乾貨很多,馬上到~

1.基本概念

1.1 並行和併發

這個概念在之前的博客中,我也講過多次了。之類再做個簡單的概述。
併發是指宏觀上在一段時間內能同時運行多個程序(按時間片交叉運行),而並行則指同一時刻能運行多個指令。

並行需要硬件支持,如多流水線、多核處理器或者分佈式計算系統。
操作系統通過引入進程和線程,使得程序能夠併發運行。

1.2 共享

共享是指系統中的資源可以被多個併發進程共同使用。

有兩種共享方式:互斥共享和同時共享

互斥共享的資源稱爲臨界資源,例如打印機等,在同一時間只允許一個進程訪問,需要用同步機制來實現對臨界資源的訪問。

1.3 虛擬

虛擬技術把一個物理實體轉換爲多個邏輯實體。

主要有兩種虛擬技術:時分複用技術和空分複用技術。

多個進程能在同一個處理器上併發執行使用了時分複用技術,讓每個進程輪流佔有處理器,每次只執行一小個時間片並快速切換。

虛擬內存使用了空分複用技術,它將物理內存抽象爲地址空間,每個進程都有各自的地址空間。地址空間的頁被映射到物理內存,地址空間的頁並不需要全部在物理內存中,當使用到一個沒有在物理內存的頁時,執行頁面置換算法,將該頁置換到內存中。

1.4 異步

異步指進程不是一次性執行完畢,而是走走停停,以不可知的速度向前推進。

2.操作系統的基本功能

  • 進程管理(有些書裏面也將他說爲處理機管理)
    進程控制、進程同步、進程通信、死鎖處理、處理機調度等。

  • 內存管理
    內存分配、地址映射、內存保護與共享、虛擬內存等。

  • 文件管理
    文件存儲空間的管理、目錄管理、文件讀寫管理和保護等。

  • 設備管理
    完成用戶的 I/O 請求,方便用戶使用各種設備,並提高設備的利用率。
    主要包括緩衝管理、設備分配、設備處理、虛擬設備等。

後面的內容大多會圍繞這幾個方面進行展開論述。

3.進程管理

3.1 進程和線程

進程是資源分配的基本單位

進程的組成部分有:
①程序。作用:描述進程要完成的功能。
②數據集合。作用:程序在執行時所需要的數據和工作區。
③程序控制塊。作用:包含進程的描述信息和控制信息。它是進程存在的唯一標誌。

進程控制塊 (Process Control Block, PCB) 描述進程的基本信息和運行狀態,所謂的創建進程和撤銷進程,都是指對 PCB 的操作。

線程是獨立調度的基本單位。一個進程中可以有多個線程,它們共享進程資源。

例如:QQ 和瀏覽器是兩個進程,瀏覽器進程裏面有很多線程,例如 HTTP 請求線程、事件響應線程、渲染線程等等,線程的併發執行使得在瀏覽器中點擊一個新鏈接從而發起 HTTP 請求時,瀏覽器還可以響應用戶的其它事件。

3.2進程和線程的區別(重要!!)

  • 擁有資源
    進程是資源分配的基本單位,但是線程不擁有資源,線程可以訪問隸屬進程的資源。
  • 調度
    線程是獨立調度的基本單位,在同一進程中,線程的切換不會引起進程切換,從一個進程中的線程切換到另一個進程中的線程時,會引起進程切換。
  • 併發
    不僅進程之間可以併發執行,多個線程之間也可以併發執行,提高吞吐量。
  • 系統開銷
    由於創建或撤銷進程時,系統都要爲之分配或回收資源,如內存空間、I/O 設備等,所付出的開銷遠大於創建或撤銷線程時的開銷。類似地,在進行進程切換時,涉及當前執行進程 CPU 環境的保存及新調度進程 CPU 環境的設置,而線程切換時只需保存和設置少量寄存器內容,開銷很小。
  • 通信方面
    線程間可以通過直接讀寫同一進程中的數據進行通信,但是進程通信需要藉助 IPC。

3.3 進程的狀態

在這裏插入圖片描述

3.4進程調度算法

不同環境的調度算法目標不同,因此需要針對不同環境來討論調度算法。

1. 批處理系統

批處理系統沒有太多的用戶操作,在該系統中,調度算法目標是保證吞吐量和週轉時間(從提交到終止的時間)。

1.1 先來先服務 first-come first-serverd(FCFS)
按照請求的順序進行調度。
有利於長作業,但不利於短作業,因爲短作業必須一直等待前面的長作業執行完畢才能執行,而長作業又需要執行很長時間,造成了短作業等待時間過長。

1.2 短作業優先 shortest job first(SJF)
按估計運行時間最短的順序進行調度。
長作業有可能會餓死,處於一直等待短作業執行完畢的狀態。因爲如果一直有短作業到來,那麼長作業永遠得不到調度。

1.3 最短剩餘時間優先 shortest remaining time next(SRTN)
按估計剩餘時間最短的順序進行調度。

2. 交互式系統

交互式系統有大量的用戶交互操作,在該系統中調度算法的目標是快速地進行響應。

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

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

  • 因爲進程切換都要保存進程的信息並且載入新進程的信息,如果時間片太小,會導致進程切換得太頻繁,在進程切換上就會花過多時間。
  • 而如果時間片過長,那麼實時性就不能得到保證。
    在這裏插入圖片描述
    2.2 優先級調度
    爲每個進程分配一個優先級,按優先級進行調度。
    爲了防止低優先級的進程永遠等不到調度,可以隨着時間的推移增加等待進程的優先級。

2.3 多級反饋隊列
一個進程需要執行 100 個時間片,如果採用時間片輪轉調度算法,那麼需要交換 100 次。
多級隊列是爲這種需要連續執行多個時間片的進程考慮,它設置了多個隊列,每個隊列時間片大小都不同,例如 1,2,4,8,…。進程在第一個隊列沒執行完,就會被移到下一個隊列。這種方式下,之前的進程只需要交換 7 次。
每個隊列優先權也不同,最上面的優先權最高。因此只有上一個隊列沒有進程在排隊,才能調度當前隊列上的進程。
可以將這種調度算法看成是時間片輪轉調度算法和優先級調度算法的結合。
在這裏插入圖片描述

3. 實時系統

實時系統要求一個請求在一個確定時間內得到響應。
分爲硬實時和軟實時,前者必須滿足絕對的截止時間,後者可以容忍一定的超時。

3.5 進程同步

多進程雖然提高了系統資源利用率和吞吐量,但是由於進程的異步性可能造成系統的混亂。進程同步的任務就是對多個相關進程在執行順序上進行協調,使併發執行的多個進程之間可以有效的共享資源和相互合作,保證程序執行的可再現性

同步機制需要遵循的原則:

  1. 空閒讓進:當沒有進程處於臨界區的時候,應該許可其他進程進入臨界區的申請
  2. 忙則等待:當前如果有進程處於臨界區,如果有其他進程申請進入,則必須等待,保證對臨界區的互斥訪問
  3. 有限等待:對要求訪問臨界資源的進程,需要在有限時間呃逆進入臨界區,防止出現死等
  4. 讓權等待:當進程無法進入臨界區的時候,需要釋放處理機,邊陷入忙等
    經典的進程同步問題:生產者-消費者問題;哲學家進餐問題;讀者-寫者問題

1. 臨界區
對臨界資源進行訪問的那段代碼稱爲臨界區。

爲了互斥訪問臨界資源,每個進程在進入臨界區之前,需要先進行檢查。

2. 同步與互斥
同步:多個進程按一定順序執行;
互斥:多個進程在同一時刻只有一個進程能進入臨界區。

3. 信號量
信號量(Semaphore)是一個整型變量,可以對其執行 down 和 up 操作,也就是常見的 P 和 V 操作。

  • down : 如果信號量大於 0 ,執行 -1 操作;如果信號量等於 0,進程睡眠,等待信號量大於 0;
  • up :對信號量執行 +1 操作,喚醒睡眠的進程讓其完成 down 操作。

down 和 up 操作需要被設計成原語,不可分割,通常的做法是在執行這些操作的時候屏蔽中斷。

如果信號量的取值只能爲 0 或者 1,那麼就成爲了 互斥量(Mutex) ,0 表示臨界區已經加鎖,1 表示臨界區解鎖。

typedef int semaphore;
semaphore mutex = 1;
void P1() {
    down(&mutex);
    // 臨界區
    up(&mutex);
}

void P2() {
    down(&mutex);
    // 臨界區
    up(&mutex);
}

使用信號量實現生產者-消費者問題
問題描述:使用一個緩衝區來保存物品,只有緩衝區沒有滿,生產者纔可以放入物品;只有緩衝區不爲空,消費者纔可以拿走物品。

因爲緩衝區屬於臨界資源,因此需要使用一個互斥量 mutex 來控制對緩衝區的互斥訪問。

爲了同步生產者和消費者的行爲,需要記錄緩衝區中物品的數量。數量可以使用信號量來進行統計,這裏需要使用兩個信號量:empty 記錄空緩衝區的數量,full 記錄滿緩衝區的數量。其中,empty 信號量是在生產者進程中使用,當 empty 不爲 0 時,生產者纔可以放入物品;full 信號量是在消費者進程中使用,當 full 信號量不爲 0 時,消費者纔可以取走物品。

注意,不能先對緩衝區進行加鎖,再測試信號量。也就是說,不能先執行 down(mutex) 再執行 down(empty)。如果這麼做了,那麼可能會出現這種情況:生產者對緩衝區加鎖後,執行 down(empty) 操作,發現 empty = 0,此時生產者睡眠。消費者不能進入臨界區,因爲生產者對緩衝區加鎖了,消費者就無法執行 up(empty) 操作,empty 永遠都爲 0,導致生產者永遠等待下,不會釋放鎖,消費者因此也會永遠等待下去。

#define N 100
typedef int semaphore;
semaphore mutex = 1;
semaphore empty = N;
semaphore full = 0;

void producer() {
    while(TRUE) {
        int item = produce_item();
        down(&empty);
        down(&mutex);
        insert_item(item);
        up(&mutex);
        up(&full);
    }
}

void consumer() {
    while(TRUE) {
        down(&full);
        down(&mutex);
        int item = remove_item();
        consume_item(item);
        up(&mutex);
        up(&empty);
    }
}

4. 管程
使用信號量機制實現的生產者消費者問題需要客戶端代碼做很多控制,而管程把控制的代碼獨立出來,不僅不容易出錯,也使得客戶端代碼調用更容易。

c 語言不支持管程,下面的示例代碼使用了類 Pascal 語言來描述管程。示例代碼的管程提供了 insert() 和 remove() 方法,客戶端代碼通過調用這兩個方法來解決生產者-消費者問題。

monitor ProducerConsumer
    integer i;
    condition c;

    procedure insert();
    begin
        // ...
    end;

    procedure remove();
    begin
        // ...
    end;
end monitor;

管程有一個重要特性:在一個時刻只能有一個進程使用管程。進程在無法繼續執行的時候不能一直佔用管程,否者其它進程永遠不能使用管程。

管程引入了條件變量以及相關的操作:wait() 和 signal() 來實現同步操作。對條件變量執行 wait() 操作會導致調用進程阻塞,把管程讓出來給另一個進程持有。signal() 操作用於喚醒被阻塞的進程。

使用管程實現生產者-消費者問題

// 管程
monitor ProducerConsumer
    condition full, empty;
    integer count := 0;
    condition c;

    procedure insert(item: integer);
    begin
        if count = N then wait(full);
        insert_item(item);
        count := count + 1;
        if count = 1 then signal(empty);
    end;

    function remove: integer;
    begin
        if count = 0 then wait(empty);
        remove = remove_item;
        count := count - 1;
        if count = N -1 then signal(full);
    end;
end monitor;

// 生產者客戶端
procedure producer
begin
    while true do
    begin
        item = produce_item;
        ProducerConsumer.insert(item);
    end
end;

// 消費者客戶端
procedure consumer
begin
    while true do
    begin
        item = ProducerConsumer.remove;
        consume_item(item);
    end
end;

生產者和消費者問題前面已經討論過了。

1. 讀者-寫者問題
允許多個進程同時對數據進行讀操作,但是不允許讀和寫以及寫和寫操作同時發生。

一個整型變量 count 記錄在對數據進行讀操作的進程數量,一個互斥量 count_mutex 用於對 count 加鎖,一個互斥量 data_mutex 用於對讀寫的數據加鎖。

typedef int semaphore;
semaphore count_mutex = 1;
semaphore data_mutex = 1;
int count = 0;

void reader() {
    while(TRUE) {
        down(&count_mutex);
        count++;
        if(count == 1) down(&data_mutex); // 第一個讀者需要對數據進行加鎖,防止寫進程訪問
        up(&count_mutex);
        read();
        down(&count_mutex);
        count--;
        if(count == 0) up(&data_mutex);
        up(&count_mutex);
    }
}

void writer() {
    while(TRUE) {
        down(&data_mutex);
        write();
        up(&data_mutex);
    }
}

在這裏插入圖片描述

3.6 進程通信(重要!!)

進程同步與進程通信很容易混淆,它們的區別在於:

  • 進程同步:控制多個進程按一定順序執行;
  • 進程通信:進程間傳輸信息。

進程通信就是指進程間的信息交換,交換信息可以使一個狀態,也可以是很多的byte。進程間同步互斥也存在信息的交換,因此也屬於是一種IPC,屬於是低級通信。該低級通信存在的問題:1)通信的數據量太少;2)通信對用戶不透明(數據的傳遞或者同步互斥都需要程序員實現)

高級通信機制(高級通信的通信細節被OS隱藏,因此使用起來增加方便而且可以傳送大量的數據,尤其是管道通信):

  • 1.共享內存(最快的方式)
    相互通信的進程共享某些數據結構或者是存儲區,進程之間可以通過這些共享空間進行通信。分爲:1)基於共享數據結構的通信,如生產者消費者系統中的有界緩衝區;2)基於共享存儲區的通信,可以傳輸大量數據,通信的進程之間可以像讀寫普通存儲器一樣讀寫共享存儲區
  • 2.消息傳遞系統
    進程間通信採用的是格式化的消息,可以直接使用OS提供的消息發送或者接受原語進行通信。由於隱藏了通信細節,所以簡化了通信程序的複雜性
  • 3.管道通信
    管道是連接兩個一個讀進程和一個寫進程之間用於實現數據交換的一個共享文件。爲了協調管道通信雙方,需要管道機制實現如下功能:1)互斥:統一時刻只能有一個進程對管道進行讀寫;2)同步:當讀端發現管道爲空的時候需要睡眠等待,直到有數據時候被喚醒,相應的寫端也是在管道已滿的時候等待直到被喚醒;3)確定對方的存在性:只有同時有讀端和寫端,管道纔有存在意義
  • 4.信號量
    進程間通信處理同步互斥的機制。信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作爲一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。(關鍵就是通過PV操作)

3.7 孤兒進程和僵死進程

(1)孤兒進程:一個父進程退出,而它的一個或多個子進程還在運行,那麼那些子進程將成爲孤兒進程。孤兒進程將被init進程(進程號爲1)所收養,並由init進程對它們完成狀態收集工作。

危害:由於父進程已經死亡,系統會幫助父進程回收處理孤兒進程。所以孤兒進程實際上是不佔用資源的,因爲它終究是被系統回收了。不會像殭屍進程那樣佔用ID,損害運行系統

(2)僵死進程:一個進程使用fork創建子進程,如果子進程退出,而父進程並沒有調用wait或waitpid獲取子進程的狀態信息,那麼子進程的進程描述符仍然保存在系統中。這種進程稱之爲僵死進程

危害:如果進程不調用wait / waitpid的話, 那麼保留的那段信息就不會釋放,其進程號就會一直被佔用,但是系統所能使用的進程號是有限的,如果大量的產生僵死進程,將因爲沒有可用的進程號而導致系統不能產生新的進程. 此即爲殭屍進程的危害,應當避免。

危害的場景:例如有個進程,它定期的產 生一個子進程,這個子進程需要做的事情很少,做完它該做的事情之後就退出了,因此這個子進程的生命週期很短,但是,父進程只管生成新的子進程,至於子進程 退出之後的事情,則一概不聞不問,這樣,系統運行上一段時間之後,系統中就會存在很多的僵死進程,倘若用ps命令查看的話,就會看到很多狀態爲Z的進程。 嚴格地來說,僵死進程並不是問題的根源,罪魁禍首是產生出大量僵死進程的那個父進程。因此,當我們尋求如何消滅系統中大量的僵死進程時,答案就是把產生大 量僵死進程的那個元兇槍斃掉(也就是通過kill發送SIGTERM或者SIGKILL信號啦)。槍斃了元兇進程之後,它產生的僵死進程就變成了孤兒進 程,這些孤兒進程會被init進程接管,init進程會wait()這些孤兒進程,釋放它們佔用的系統進程表中的資源,這樣,這些已經僵死的孤兒進程 就能瞑目而去了

4.死鎖

4.1 死鎖的必要條件和處理方法

定義:死鎖是指多個進程在運行過程中,因爲爭奪資源而造成的一種僵局,如果沒有外力推進,處於僵局中的進程就無法繼續執行。

死鎖原因:

  1. 競爭資源:請求同一有限資源的進程數多於可用資源數
  2. 進程推進順序非法:進程執行中,請求和釋放資源順序不合理,如資源等待鏈

死鎖產生的必要條件:

  1. 互斥條件:進程對所分配的資源進行排他性的使用
  2. 請求和保持條件:進程被阻塞的時候並不釋放鎖申請到的資源
  3. 不可剝奪條件:進程對於已經申請到的資源在使用完成之前不可以被剝奪
  4. 環路等待條件:發生死鎖的時候存在的一個 進程-資源 環形等待鏈

死鎖處理:

  1. 預防死鎖:破壞產生死鎖的4個必要條件中的一個或者多個;實現起來比較簡單,但是如果限制過於嚴格會降低系統資源利用率以及吞吐量
  2. 避免死鎖:在資源的動態分配中,防止系統進入不安全狀態(可能產生死鎖的狀態)-如銀行家算法
  3. 檢測死鎖:允許系統運行過程中產生死鎖,在死鎖發生之後,採用一定的算法進行檢測,並確定與死鎖相關的資源和進程,採取相關方法清除檢測到的死鎖。實現難度大
  4. 解除死鎖:與死鎖檢測配合,將系統從死鎖中解脫出來(撤銷進程或者剝奪資源)。對檢測到的和死鎖相關的進程以及資源,通過撤銷或者掛起的方式,釋放一些資源並將其分配給處於阻塞狀態的進程,使其轉變爲就緒態。實現難度大

死鎖定理:S爲死鎖狀態的充分條件是,當且僅當S的資源分配圖是不能完全簡化的。

4.2 說說進程的飢餓和死鎖的區別?

它們兩者都是進程與進程之間存在的兩種資源競爭的狀態:

死鎖:如果一個進程集合中的每個進程都在等待只能由該組進程中的其他進程才能引發的事件,那麼,該組進程是死鎖的。

飢餓:主要就是指存在某些進程永遠得不到服務的機會。比如多個文件進行請求打印機設備分配打印機問題。如果首先分配給小文件,那麼大文件可能永遠得不到打印。對於這問題,比較好的解決方法就是通過先來先服務方式。

5.內存管理

5.1 虛擬存儲器出現的原因以及其主要的思想?

出現的原因:遇到程序太大,以至於內存容納不下,而必須進行分段進行載入內存
基本思想:程序,數據和堆棧的總大小可能超過可用的物理內存的大小。由操作系統把程序當前使用的那部分保留在主存中,而把其他的部分保存在磁盤上。這樣就實現用小的內存大小來運行大的程序。

5.2 物理地址和虛擬地址分別指什麼?

物理地址:就是內存中實際存在的地址,也就是我們電腦中內存條中所表示的地址。

虛擬地址:被分成虛擬頁號(高位)和偏移量(低位)是一種虛擬化的地址,是由程序產生的地址。虛擬地址與物理地址不是一一對應關係,它們之間存在映射關係。而轉換就是通過MMU(其中MMU(內存管理單元):作用爲把虛擬地址映射爲物理內存地址)來進行。

5.3 什麼叫做虛擬內存?虛擬存儲器的特徵是什麼?

如果存在一個程序,所需內存空間超過了計算機可以提供的實際內存,那麼由於該程序無法裝入內存所以也就無法運行。單純的增加物理內存只能解決一部分問題,但是仍然會出現無法裝入單個或者無法同時裝入多個程序的問題。但是可以從邏輯的角度擴充內存容量,即可解決上述兩種問題,所以出現了虛擬內存;

虛擬存儲器定義:就是具有請求調入功能和置換功能,可以從邏輯上對內存容量加以擴充的一種存儲器系統。虛擬存儲器都是建立在離散內存管理的基礎上。

虛擬存儲器的特徵

  1. 多次性:一個作業可以分多次被調入內存。多次性是虛擬存儲特有的屬性
  2. 對換性:作業運行過程中存在換進換出的過程(換出暫時不用的數據換入需要的數據)
  3. 虛擬性:虛擬性體現在其從邏輯上擴充了內存的容量(可以運行實際內存需求比物理內存大的應用程序)。虛擬性是虛擬存儲器的最重要特徵也是其最終目標。虛擬性建立在多次性和對換性的基礎上行,多次性和對換性又建立在離散分配的基礎上

5.4 頁表是什麼?頁表的表項有哪些結構?頁面的抖動和顛簸又是指什麼?

頁表:把虛擬地址映射到頁幀。(每個進程都有自己的頁表,因爲每個進程都有自己的虛擬空間)
頁表的結構:(1)高速緩存禁止位:標識是否被緩存
(2)訪問位:標識是否被訪問,主要是作用於頁面置換
(3)修改位:爲了記錄頁面的使用狀況,用於標識是否被修改過
(4)保護位:指出一個頁面允許什麼類型的訪問
(5)"在/不在"位:標識是否處於內存中,如果不在,就需要從磁盤進行載入內存
(6)頁幀號

頁面抖動:剛剛換出的頁面可能又被接下來訪問。
頁面顛簸:每執行幾條程序語句,就會發生頁面失效(缺頁)的情況。

5.5 頁面置換算法有哪些?

(1)最佳置換算法:只具有理論意義的算法,用來評價其他頁面置換算法。置換策略是將當前頁面中在未來最長時間內不會被訪問的頁置換出去。
(2)先進先出置換算法:簡單粗暴的一種置換算法,沒有考慮頁面訪問頻率信息。每次淘汰最早調入的頁面
(3)最近最久未使用算法LRU:算法賦予每個頁面一個訪問字段,用來記錄上次頁面被訪問到現在所經歷的時間t,每次置換的時候把t值最大的頁面置換出去(實現方面可以採用寄存器或者棧的方式實現)
(4)時鐘算法clock(也被稱爲是最近未使用算法NRU):頁面設置一個訪問爲,並將頁面鏈接爲一個環形隊列,頁面被訪問的時候訪問位設置爲1。頁面置換的時候,如果當前指針所指頁面訪問爲爲0,那麼置換,否則將其置爲0,循環直到遇到一個訪問爲位0的頁面
(5)改進型Clock算法:在Clock算法的基礎上添加一個修改位,替換時根究訪問位和修改位綜合判斷。優先替換訪問爲何修改位都是0的頁面,其次是訪問位爲0修改位爲1的頁面。
(6)最少使用算法LFU:設置寄存器記錄頁面被訪問次數,每次置換的時候置換當前訪問次數最少的。存在問題是該訪問寄存器並不能真正反映當前頁面訪問次數,因爲訪問速度比較快,所以在更新寄存器的時間間隔內訪問1次和訪問100次都是一樣的。另外,LFU和LRU是很類似的,支持硬件也是一樣的,但是區分兩者的關鍵在於一個以時間爲標準,一個以次數爲標準(例如對於寄存器 pa 001111 和pb 111000,兩個頁面,如果採用LRU,那麼被淘汰的是pa,如果採用LFU那麼被淘汰的是pb)。
(7)頁面緩衝算法PBA:置換的時候,頁面無論是否被修改過,都不被置換到磁盤,而是先暫留在內存中的頁面鏈表(已修改頁面鏈表和未修改頁面鏈表,也可以不區分)裏面,當其再次被訪問的時候可以直接從這些鏈表中取出而不必進行磁盤IO,當鏈表中已修改也難數目達到一定數量之後,進行依次寫磁盤操作(相當於將多次IO合併爲一次)

5.6 操作系統在什麼情況下會做調頁有關的工作?

(1)進程創建:操心繫統要確定程序和數據最初的大小,併爲它們創建一個頁表。
(2)進程執行:必須爲新進程重置MMU(內存管理單位)和刷新TLB(快表),以清除以前進程所留下的痕跡。
(3)頁面失效:操作系統必須通過讀硬件寄存器來確定哪個虛擬地址造成頁面失效,並且通過計算磁盤哪個頁面需要被換入。
(4)進程銷燬:操作系統必須釋放進程的頁表,頁面和頁面在磁盤所佔有的空間。

5.7內存管理方式

答:內存管理方式出現的原因:由於連續內存分配方式(單一連續分配,固定分區分配,動態分區分配,動態重定位分區分配)導致的內存利用率偏低以及內存碎片的問題,進而引出離散的內存分配方式。離散內存分配可以從OS的內存管理角度引出頁式(離散分配的基本單位是頁)管理,也可以從程序編制角度引出段式(離散分配的基本單位是段)管理。

(1)頁式
基本分頁存儲管理中不具備頁面置換功能(即沒有實現虛擬內存的功能),因此需要整個程序的所有頁面都裝入內存之後纔可以運行。因爲程序數據存儲在不同的頁面中,而頁面又離散的分佈在內存中,因此需要一個頁表來記錄邏輯地址和實際存儲地址之間的映射關係,以實現從頁號到物理塊號的映射。由於頁表也是存儲在內存中的,因此和不適用分頁管理的存儲方式相比,訪問分頁系統中內存數據需要兩次的內存訪問(一次是從內存中訪問頁表,從中找到指定的物理塊號,加上頁內偏移得到實際物理地址;第二次就是根據第一次得到的物理地址訪問內存取出數據)
爲了減少兩次訪問內存導致的效率影響,分頁管理中引入了快表(或者聯想寄存器)機制,包含快表機制的內存管理中,當要訪問內存數據的時候,首先將頁號在快表中查詢,如果查找到說明要訪問的頁表項在快表中,那麼直接從快表中讀取相應的物理塊號;如果沒有找到,那麼訪問內存中的頁表,從頁表中得到物理地址,同時將頁表中的該映射表項添加到快表中(可能存在快表換出算法)。
在某些計算機中如果內存的邏輯地址很大,將會導致程序的頁表項會很多,而頁表在內存中是連續存放的,所以相應的就需要較大的連續內存空間。爲了解決這個問題,可以採用兩級頁表或者多級頁表的方法,其中外層頁表一次性調入內存且連續存放,內層頁表離散存放。相應的訪問內存頁表的時候需要一次地址變換,訪問邏輯地址對應的物理地址的時候也需要一次地址變換,而且一共需要訪問內存3次纔可以讀取一次數據。

(2)段式
分頁是爲了提高內存利用率,而分段是爲了滿足程序員在編寫代碼的時候的一些邏輯需求(比如數據共享,數據保護,動態鏈接等)
分段內存管理當中,地址是二維的,一維是段號,一維是段內地址;其中每個段的長度是不一樣的,而且每個段內部都是從0開始編址的。由於分段管理中,每個段內部是連續內存分配,但是段和段之間是離散分配的,因此也存在一個邏輯地址到物理地址的映射關係,相應的就是段表機制。段表中的每一個表項記錄了該段在內存中的起始地址和該段的長度。段表可以放在內存中也可以放在寄存器中。
訪問內存的時候根據段號和段表項的長度計算當前訪問段在段表中的位置,然後訪問段表,得到該段的物理地址,根據該物理地址以及段內偏移量就可以得到需要訪問的內存。由於也是兩次內存訪問,所以分段管理中同樣引入了聯想寄存器。

分段和分頁的對比:
(1)對程序員的透明性:分頁透明,但是分段需要程序員顯示劃分每個段。
(2)地址空間的維度:分頁是一維地址空間,分段是二維的。
(3)大小是否可以改變:頁的大小不可變,段的大小可以動態改變。
(4)出現的原因:分頁主要用於實現虛擬內存,從而獲得更大的地址空間;分段主要是爲了使程序和數據可以被劃分爲邏輯上獨立的地址空間並且有助於共享和保護。

(3)段頁式:
先將用戶程序分爲若干個段,然後再把每個段分成若干個頁,並且爲每一個段賦予一個段名稱。這樣在段頁式管理中,一個內存地址就由段號,段內頁號以及頁內地址三個部分組成。

段頁式內存訪問:系統中設置了一個段表寄存器,存放段表的起始地址和段表的長度。地址變換時,根據給定的段號(還需要將段號和寄存器中的段表長度進行比較防止越界)以及寄存器中的段表起始地址,就可以得到該段對應的段表項,從段表項中得到該段對應的頁表的起始地址,然後利用邏輯地址中的段內頁號從頁表中找到頁表項,從該頁表項中的物理塊地址以及邏輯地址中的頁內地址拼接出物理地址,最後用這個物理地址訪問得到所需數據。由於訪問一個數據需要三次內存訪問,所以段頁式管理中也引入了高速緩衝寄存器。

參考資料:
1.湯子瀛, 哲鳳屏, 湯小丹. 計算機操作系統[M]. 西安電子科技大學出版社, 2001.
2. CS-Notes
3. 手把手教你如何玩轉面試(操作系統)

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