考研—作業系統—記憶體管理
綜述:記憶體管理在計算機組成原理和作業系統都是重點。計算機的核心部件就是cpu和主存,其他的都是配件。所以作業系統需要進一步管理主存資源,這裡涉及更加具體的頁式管理,段頁式管理,以及虛擬記憶體。
記憶體管理概念
什麼是記憶體管理?為什麼要記憶體管理?
作業系統的記憶體管理就是對記憶體合理的使用,動態的規劃,通過管理也可以叫做控制,可以讓記憶體達到最高的利用率。是一種智慧干預的方式,提高了記憶體使用率。為什麼要記憶體管理那?因為記憶體還是不夠用。
記憶體管理的主要功能:
1)記憶體空間的分配與回收
2)地址轉換(邏輯地址與實體地址)
3)記憶體空間的擴充(利用虛擬技術)
4)記憶體保護
程序執行的原理
建立程序首先要將程式和資料裝入記憶體,才能將源程式變成可以在記憶體中執行的程式。首先要編譯(由編譯程式將使用者原始碼轉換為若干目標模組),然後要連結(由連結程式將編譯後形成的一組目標模組以及所需要庫函式連結到一起),最後裝入,將整個裝入模組裝入記憶體。接下來詳細介紹這三個步驟。
編譯:編譯就是把使用者使用的高階語言程式碼轉化為彙編程式,轉化成為更底層的程式。
連結:程式連結就是將編譯好的目標模組連結上必要的庫函式。有三種連結方式:
1、靜態連結:在裝入記憶體之前把所有需要的庫函式連結成一個完整的可執行程式,以後將不再開啟。
2、裝入時動態連結
3、執行時動態裝入(最佳):對某些大型的軟體,所需要的庫函式比較多,但是並不是每個模組都用得到。所以採用,在用這個模組的時候再連結上庫函式。
裝入:裝入記憶體也有三種不同的方法
1、絕對裝入,實際地址是程式碼中直接給出的,是固定的,也是靜態的。所有很簡單直接按照地址裝入就行。只適合單道程式的環境。
2、可重定位裝入,在多道程式環境下,多個目標模組的起始地址通常都是從0開始的,所以我們把0開始的地址叫作邏輯地址,這就需要重新定位轉換成實體地址,才能把程式放到合適的記憶體空間中。此種方法也稱為靜態重定位,一次必須分配足夠程式執行的記憶體空間。並且在整個執行過程中,不能移動地址。
3、動態執行時裝入(動態重定位),相比於靜態重定位,在裝入後,並不轉換邏輯地址為實體地址,而是在需要執行的時候,才轉換。因此裝入記憶體後的地址依舊是邏輯地址。這種方式需要一個重定位暫存器來記錄如何轉換成實體地址。通過這種方法,程式可以分配到不連續的儲存區間,可以使用邏輯上更大地址空間。程式在初次建立的時候只申請一部分記憶體空間,根據需要動態申請分配記憶體。
邏輯地址和實體地址
邏輯地址是作業系統上層的程式使用的地址,實體地址是計算機中記憶體的地址。而中間就是作業系統,作業系統負責轉換地址。這樣不僅可以方便使用者和應用程式猿,並且可以通過虛擬技術使用更大的邏輯地址空間。而對於作業系統,就負責轉換這些地址,從邏輯地址轉換到實體地址的過程就是重定位。
記憶體保護
記憶體保護有兩層意思1、作業系統不能被使用者程序影響(保護作業系統)2、使用者程序之間不能互相影響。
有兩種辦法:
1)簡單辦法:設定一對上下限暫存器,預設作業使用的地址是連續,上下限暫存器中儲存著上限地址和下限地址,每次執行前要判斷有沒有越界。(雖然簡單,但是地址必須是連續的)
2)使用重定位暫存器和界地址暫存器來實現這種記憶體保護。重定位地址的功能是用來轉換邏輯地址的,因為地址在物理上可能不連續,所以我們在邏輯地址上來判斷有無越界。如果判斷通過,則通過界地址暫存器轉換為實體地址。
覆蓋與交換(用來擴充記憶體的技術)
覆蓋已經過時是交換技術的過渡版本。
交換(對換):交換的基本思想就是把記憶體中的暫時在等待狀態的程序從記憶體中調到輔存中去。把記憶體空間騰出來叫換出,再把準備好競爭cpu資源的程序放進記憶體,這叫換入。
交換需要注意以下幾個問題:
1、交換需要備份儲存。
2、為了有效使用cpu,執行時間要比交換時間長的多
3、如果換出程序,必須保證程序是空閒的。
4、交換所用的空間是磁碟的一塊,是獨立於檔案系統的。
5、交換通常用於在有許多程序執行且記憶體空間不夠的時候使用。
6、普通的交換使用並不多,但是此種方法的變種很多。、
ps:現代作業系統主要是使用虛擬記憶體的方式來解決記憶體不足的問題。
兩種記憶體分配管理方式
一、連續分配管理方式
連續分配就是為一個使用者程序分配一個連續的記憶體空間,有三種具體的方式。
1)單一連續分配
此種方式下,記憶體空間分為系統區和使用者區,系統區在低地址,給作業系統用,而使用者區使用其他的空間。只適合於單道程式系統。
2)固定分割槽分配
將記憶體空間分割槽,可以是大小相等的,也可以是大小不等的。每個分割槽只能裝入一個作業,互不干擾。每當有區空閒時,就迴圈裝入程序。這種方法有兩個問題一個就是程序所需要的記憶體太大,最大的區都裝不進去的時候,程序將永遠無法執行。還有一個是因為以區為單位,那麼每個區只能裝一個程序,那麼每個區都或多或少有冗餘(內部碎片)。儲存器利用率很低。這是一種最簡單的多工處理的記憶體分配方式,但是效率不行。(作業系統不使用這種辦法,這種方法還在用於簡單的控制型計算機)
3)動態分割槽分配
顧名思義,這是一種分割槽大小可變的記憶體分配方式。每個程序申請分配記憶體空間的時候,系統會給分配給程序大小完全合適的一個區,就避免了內部碎片。動態分割槽一開始的時候,效率很高,但是隨著時間的推移,記憶體利用率開始變低,因為每次都分配一段正好的空間作為一個區,那麼隨著程序的來來回回,不可能保證每個區都是連續的,剛開始可能區與區之間的空間還比較大,還能夠使用,但是時間越久,這種空間越來越小,導致最小的程序也用不了的時候,就稱之為外部碎片。這種碎片增多,記憶體的利用率就會降低。解決外部碎片可以使用緊湊的方法,就是隔一段時間,移動一下,可是移動和整理可不是人推一推就可以了,計算機進行這項工作的時候,是非常的費時的。
因此,要想動態分割槽分配的方法可以更好的使用,就需要思考,以怎樣的演算法來分配記憶體空間可以減少外部碎片的冗餘那。有四種分配方式:
1、首次適應演算法:簡單粗暴,分配記憶體的時候,順序查詢,找到第一個能用的空間,就用。
2、最佳適應演算法:空閒分割槽按容量遞增的方式排號,程序找到一個最小的能滿足自己的空閒分割槽。
3、最壞適應演算法:空閒分割槽按容量遞減的方式排號,程序找到一個
最大的能滿足自己的空閒分割槽。
4、鄰近適應演算法:也稱迴圈首次適應演算法,是首次適應演算法的增強版,不再每次都從頭開始查詢,而是從上次分配的地方開始。
效能分析:
(首次>最佳)>最壞
鄰近適應演算法嘗試解決,但是失敗了,效能很差。
最佳適應演算法產生最多的外部碎片。
總體上,反而是最簡單的首次是最好的。
二、非連續分配管理方式
非連續的方式允許同一程序分佈在不連續的記憶體空間中。相比於連續的方式,可以讓需要更大記憶體空間的程序執行。但是由於需要索引表連線不連續的空間,所以儲存密度是低於連續的方式的(就像陣列和連結串列的區別)。同樣,非連續的分配管理方式也有三種方式:
1)基本分頁管理方式
首先把記憶體空間分割成大小相等的塊,作為主存的最基本的單位。這裡的塊在不同的情況有不同的名字。程序中的塊,即使用中的塊,稱為頁。而記憶體中的塊,即沒有使用的塊,稱為頁框。外存中的塊就叫塊。
有的同學可能會疑惑,這跟連續中的固定分割槽方法有什麼不一樣嗎?這其中可能有些相似,但是本質思想是很大不一樣的。連續分配方式中的固定分割槽,是整體,是可以裝進整個程序的大小的單位。而這裡的塊是相對小很多的,是組成程序的大小單位。這其中的區別是非常大的。舉個例子,假如程序平均大小在80左右浮動,一般不超過100.那麼我們可以用固定分割槽的方式,把區的大小設定為100,就可以很好的裝下這些程序。而在這種方式中,塊的大小可能就是1,一個程序需要80的記憶體空間,就需要申請80個塊。這樣的方式會大大的減少內部碎片。
1、分頁分配方式的地址格式
地址結構主要由頁號和頁內偏移量組成。首先要明白,地址是什麼的地址,這裡的地址是記憶體空間中的位元組的地址。那麼該如何用這兩個資訊來表示位元組的地址那?頁號就是塊的編號,記憶體中的所有的塊有一個唯一的快號。這裡的頁號是可以通過下文中的頁表的形式來轉換為唯一額塊號的。有了頁號就能找到那個唯一的塊。然後頁內偏移量就是塊內部位元組的編號了,從頭開始往後,就能通過這個地址找到唯一的位元組了。在說什麼是頁表之前,首先要明白,什麼是頁號什麼是塊號,為什麼兩者要進行轉換?頁號就相當於邏輯地址,而塊號就相當於實體地址,所以需要頁表來進行轉換。頁表中會存放著頁號和塊號對應的關係。
2、基本地址變換機構
即各種號是如何計算的,以及如何轉換的。
在系統中要有一個頁表暫存器,存放著頁表的起始地址F和頁表長度M。在程序執行之前,這兩個資訊還在PCB中,執行時放入頁表暫存器。頁面大小為L,那麼邏輯地址A和實體地址E的轉換過程就是這樣的。
(1)分別計算出頁號和頁內偏移量
頁號=邏輯地址/頁面長度
頁內偏移量=邏輯地址%頁面長度
(2)比較頁號和頁表長度,若頁號大於頁表長度,說明越界,則中斷。
(3)頁表項地址=頁表起始地址+頁號*頁表項長度,計算出頁表項地址後,取出地址中的內容,這個內容就是塊號。
(4)計算實體地址=塊號*頁面大小+業內偏移量,則得到實體地址
3、快表
頁式管理的主要問題:地址轉換必須很快,否則會降低速度。另一個問題就是頁表不能太大,否則記憶體利用率就會很低。為了提高業式管理的效率,故引入快表。顧名思義,快表就是很快的頁表。快表就是將部分正在用的頁表放進cache中,以達到更快的速度。所以放在記憶體中的頁表就叫做慢表。這樣,帶有快表的地址變換就成為,cpu給出的邏輯地址,硬體計算出頁號後是給cache的,通過cache計算出實體地址,然後去訪存,所以只需要一次訪存。快表的命中率可以達到90%左右,這樣可以有效的降低分頁式定址上的時間損耗。
4、兩級頁表
為了解決頁表太長的問題,一級頁表已經無法滿足我們了。所以我們設計出兩級頁表。可以壓縮頁表長度,即使用層次結構的頁表。實際上二級頁表就是建造頁表的頁表。為了提高效率,最高階的頁表只能有一頁,這樣就可以快很多,我們把頂級頁表放在cache中。那麼邏輯地址的格式就會變為,一級頁號、二級頁號、頁內偏移。
2)基本分段管理方式
設計原因是頁的不足,頁是對於計算機的角度設計的,人是很難使用的,因為頁沒有邏輯,只有頁號,一個程序,一段程式碼,我們只能用那幾頁來表示。不同的東西,卻沒辦法通過頁形成為跟別。所以我們設計了一種以邏輯段為單位的分段管理方式。
1、分段,把程序的各個部分按照功能不同分段,比如資料段,程式碼段,堆疊段。然後每個段分配一段連續的空間,段內連續,段間不連續。其邏輯地址由段號和段內偏移量組成。
2、段表,段表中記錄著段表項在記憶體中的地址。段表內容為段號、段長、本段在記憶體中的起始地址。這樣就可以通過查詢段表來找到段內資訊的實體地址。
3、地址轉換,同樣的設定一個段表暫存器,存著段表起始地址和段表長度,這裡的段表長度的單位是段,表示的是幾個段,那麼段號就不能大於段長。依舊是通過段表的起始地址加上段號*段表項長度得到我們段表中的資訊,獲得段起始地址後,我們就可以通過段內偏移量得到實體地址。
【缺點】頁式可以提高效率,但是沒有邏輯性,段具有邏輯性,但是缺乏效率。
【ps】段和頁的記憶體保護主要是通過限制存取和地址越界保護來實現的。
3)段頁式管理方式
為了既有頁的優點,又有段的優點,就有了段頁式管理方式。既然結合了這兩種方法,我們就在重新梳理一下對記憶體是如何改造成現在這幅模樣的。
首先我們的記憶體是以位元組為單位的,記憶體最大地址其實就是位元組數目。因為位元組太小了,所以我們有了頁式管理,把塊分成單位更大的頁,讓我們更便於管理。但是頁又缺乏邏輯性,讓我們人類很難直接使用,因為其本質不過是大一點的位元組罷了,太底層了,人很難使用。所以我們設計了段這樣的單位,那麼什麼是段頁的結合那?就是段式管理中,段的長度是多少個位元組,現在段下面的單位變成頁了,即段的長度變為幾頁了。
在段頁式管理中,為了進行地址變換,我們設定了一個段表和若干個頁表,隨之而變換的位元組的邏輯地址格式變為段號、頁號、頁內偏移量。在進行地址變換中,通過段表查詢到頁表起始地址,然後通過頁表找出塊號,找到實體地址。所以段頁式進行一次訪問要3次訪存,一次段表,一次頁表,一次真實內容。所以我們依舊可以使用快表,來減少訪存次數。
【總結】非連續的方式,就像資料結構中連結串列,而連續的方式就像陣列一樣。兩者各有優缺點。段頁也不過是通過不同的角度將記憶體空間分層,更加易於管理。
虛擬記憶體管理
虛擬記憶體出現的基礎
1)傳統儲存管理方式的侷限性:一次性(作業必須一次性裝入記憶體)、駐留性(作業被裝入記憶體就一直駐留著)
2)程式區域性性原理:時間區域性性(由於程式中含有大量迴圈操作)、空間區域性性(指令通常是順序存放、順序執行)
虛擬儲存器的定義和特徵
什麼是虛擬儲存器那?基於區域性性原理,把正在執行的程序的一部分需要執行的放入記憶體中,不用的先放在外存中,把記憶體中的空閒程序暫時的調出記憶體。這樣系統好像提供了一個大的多的記憶體。稱為虛擬儲存器。虛擬儲存器由記憶體和外存共同組成,但是其大小並不是簡單的相加。
虛擬儲存器有三個特徵:多次性(程序允許多次調入記憶體)、對換性(允許程序在執行中,換入換出)、虛擬性(從邏輯上擴充記憶體,使使用者所看到的記憶體大於實際記憶體)
虛擬儲存器實現的技術
虛擬記憶體需要將程序多次的調入記憶體中,所以連續的記憶體分配管理方式是不可以的。需要使用非連續的方式,對記憶體分散管理。
虛擬記憶體的實現有三種方式:請求分頁儲存管理、請求分段儲存管理、請求段頁式儲存管理。對應著三種非連續記憶體分配方式。
虛擬記憶體的實現不僅需要分散的記憶體分配方式,還需要硬體的支援。有以下幾個方面:
1、一定容量的記憶體和外存
2、頁表機制(或段表機制),作為主要的資料結構
3、中斷機構
4、地址變換機構
請求分頁管理方式
請求分頁管理方式是基於分頁系統基礎上的,為了支援虛擬儲存器實現功能,新增了請求調頁功能和頁面置換功能。另外系統還需要提供頁表機制、缺頁中斷、地址變換機構(虛擬記憶體中的地址是邏輯地址)
1、頁表機制
由於增加了調入頁面的功能,對頁表項中增加了幾個欄位。
頁號、物理塊號、狀態位P、訪問欄位A、修改位M、外存地址
狀態位:用於指示該頁是否已經調入記憶體
訪問欄位:用於記錄本頁在一段時間內被訪問的次數,或者記錄本頁多久沒有被訪問,用於輔助頁面置換演算法來決斷(根據演算法的不同,含義不同)
修改位:標識該頁在調入記憶體後是否被修改過。
外存地址:用於指出該頁在外存上的地址,就是外存的物理塊號
2、缺頁中斷機構
在請求分頁管理方式中,每當訪問的頁不在記憶體中的時候,就會發出缺頁中斷,請求系統調入所需要的頁。如果記憶體中有空閒塊,就直接將要調入的頁放入該塊,並修改頁表項。若此時沒有空閒塊,則按照某種規則淘汰某頁,同樣修改頁表項(若淘汰的頁被修改過,則寫回外存)
特點:1)缺頁中斷屬於內部中斷2)一條指令執行期間可能產生多次缺頁中斷。
3、地址變換機構
請求分頁系統中的地址變換機構,是在分頁系統地址變換機構的基礎上,為實現虛擬記憶體,又增加了某些功能而形成的。
在進行地址變換中,先檢索快表,若找到訪問的頁,便修改頁表項中的訪問位,然後利用頁表中的物理塊號和頁內地址定址。若未找到該頁的頁表項,應該到記憶體中去查詢頁表,檢視狀態位,看該頁是否調入記憶體中,如果沒有調入則產生缺頁中斷,請求從外存把該頁調入記憶體。
【總結】地址變換就是多了修改新增的位,比如訪問位,並且沒有在快表中找到時,還需要訪問狀態位來判斷在不在記憶體裡。虛擬記憶體的方式,主要多了缺頁中斷和頁面置換。
頁面置換演算法
1、最佳置換演算法(OPT)(不實際存在)
最佳置換演算法置換的頁面是長時間不再被訪問的頁面,這樣可以獲得最低的缺頁率。但是程序是不可以預測的,所以不能實現。此演算法用來評價其他演算法。
2、先進先出頁面置換演算法(FIFO)
優先淘汰最早進入記憶體的頁面
特點:是佇列演算法,會出現Belady異常,即所分配的物理塊數增大,頁故障數不減反增的現象。
3、最近最久未使用置換演算法(LRU)
選擇最久沒有被使用的頁面淘汰
特點:效能比較好,但是需要暫存器和棧的支援,是堆疊類演算法。
4、時鐘置換演算法(最實用)(NRU)
實現起來比LRU簡單,效能最接近LRU的演算法。
簡單版本:給每一個頁設定一個實用位。當某一個頁調入主存時,就把這個位置為1。如果要進行頁替換,系統就迴圈掃描記憶體中的頁,如果是1就置為0,如果是0,就替換這個頁。(本質思想就是,使用過的1的可能性比較大,長時間不用的肯定要被系統置為0,所以優先替換為0的頁)
複雜版本:給每一個頁設定一個使用位u和一個修改位m。思想和簡單版本是一樣的。首先這樣的設定,就有4種頁面。即:
1)最近未被訪問,也未被修改(u=0,m=0)
2)最近未被訪問,但被修改(u=0,m=1)
3)最近被訪問,但未被修改(u=1,m=0)
4)最近被訪問,被修改(u=1,m=1)
這四種情況也對應了四種優先順序,系統就是依靠這樣的優先順序來選擇誰被替換掉。因此係統有幾趟掃描。
1、從指標當前位置開始,掃描,選擇第一個遇到的u=0,m=0的頁。沒有則進入第二步。
2、重新掃描,選擇第一個u=0,m=1的頁,並且,每一個沒有成功的頁,都把使用位置0,沒有則進入第三步。
3、此時所有頁使用位都是0,重第一步開始再次迴圈。
這種複雜版本,考慮了頁面是否最近被修改的情況,因為修改過的頁需要寫回外存中,比較耗時。
頁面分配策略
1、駐留集大小
對於分頁式的虛擬記憶體,在準備執行程序時,不可能把所有的頁全部調入,因此作業系統就需要決定到底讀取多少頁。即分配多大的主存空間。這需要考慮以下幾點:
1)分配程序的主存空間越少,駐留在主存空間的程序數就越多,從而可以提高處理機的時間利用率。
2)如果一個程序在主存中頁過少,缺頁率就會過高。
3)如果頁數過多,則浪費。
基於這些因素,現代os採用三種策略:
1、固定分配區域性置換:每個程序分配的物理塊是一定的,你自己缺頁,那你自己就替換自己的頁。(難以確定每個程序需要的物理塊數目,多少合適不知道,太少缺頁中斷,太多浪費)
2、可變分配全劇置換(最易於實現):為每個程序分配一定的物理塊,系統自己保留一部分空閒的物理塊,你缺頁了,系統爸爸給你。(盲目地給程序加空間,降低系統併發效能)
3、可變分配區域性置換(效果最好):為每個程序分配一定的物理塊,系統自己保留一部分空閒的物理塊,你缺頁了,你替換你自己的頁,如果你很頻繁,系統給你加物理塊,如果你缺頁率很低,系統還要剝奪一點拿走。這是一種動態的方式來獲得程序合適的物理塊數。效果最好,但是也是實現最複雜的,但是這點複雜對於整體提升的效果來說,是值得的。
2、調入頁面的時機
為確定系統將程序執行時所缺的頁面調入記憶體的時機,可採取以下兩種調頁策略。
1)預調頁策略:一次調入相鄰若干頁面,而不是一次頁面,但是調入多了又浪費,所以全靠預測能力,可是目前預測成功率很低,所以這種方法不好用,僅僅用於程序建立時,程式設計師指定先調入哪幾頁。
2)請求調頁策略:顧名思義,缺頁了,請求頁的時候調入。但是一次調入一頁效率會低一些。
【總而言之】預調頁策略是第一次程序進入記憶體時使用,請求調頁是執行過程中調入。
3、從何處調入頁面
請求分頁系統中的外存分為兩部分,一種是用於存放檔案的檔案區(我們日常使用的部分),另一種是用於存放對換頁面的對換區(對換出來的程序)。檔案區是離散分配方式,對換區是連續分配方式,故,對換區比檔案區速度快。
三種情況:
1)對換區空間大小足夠用,全部從對換區調入頁面,所以執行前把程序的有關檔案從檔案區複製到對換區。
2)對換區大小不夠,凡是不會被修改的檔案都從檔案區調入,而當換出這些頁面時,也不用寫回,但對於那些被修改的部分,被換出時存放在對換區。
3)UNIX方式:程序的所有未被執行過的頁面全部從檔案區調入,調出時均放在對換區。
【總結】系統的頁面分配策略,主要包括建立程序時分配多少主存空間,程序執行時缺頁怎麼處理,調入時一次調入幾頁,從外存中的哪個區調入。
抖動
在頁面置換中,一種最糟糕的情況,就是抖動。抖動就是剛剛換出的頁面馬上又要換入主存,剛剛換入的頁面馬上要換出主存,頻繁的頁面排程稱為抖動。即如果一個程序的換頁時間多於程序的執行時間,就是抖動。
工作集(駐留集)
工作集就是在某段時間內,程序要訪問頁面的集合。合適的工作集大小對於系統執行效率尤為重要。
工作集模型的原理:作業系統跟蹤工作集,為程序分配大於其工作集的物理塊,如果還有物理塊空閒,就調入新的程序,如果工作集之和大於物理塊總數,則暫停一個程序。防止出現抖動。
地址翻譯(綜合計算機組成原理)
從虛擬地址到實體地址的翻譯過程
虛擬地址——快表——主存——實體地址——Cache
設某系統具體引數如下:
有一個TLB和data Cache
儲存器以位元組為編址單位
虛擬地址14位
實體地址12位
頁面大小64位元組
TLB為四路組相連,共有16個條目
data Cache是物理定址,直接對映,行大小4位元組,共有16個組
【分析】:頁面大小64B,那麼頁內偏移就是log2(64)=6位,虛擬頁號就是14-6=8位,物理頁號12-6=6位。虛擬頁號一共8位,由於TLB四路相聯,16個條目,所以16/4=4組,低2位就是tlb組的索引,高6位就是tlb的標記。實體地址,因為cache行大小4位元組,那麼低2位就是塊偏移,cache共有16組,則4位為組索引。頁內偏移的6位就是高4位組偏移,低2位是塊偏移。實體地址的高6位就是cache標記。
【實戰】
1、把給出的十六進位制虛擬地址轉換為二進位制
2、得到每個地址的組索引和TLB標記,查詢快表中的內容,若找到,則拼接頁內偏移得到實體地址
3、若沒有在快表中找到,再去找頁表。與上一步同樣。
4、若頁表也沒有找到,那就缺頁中斷。
5、得到實體地址後,去cache中尋找資料。