20145227《資訊保安系統設計基礎》第十四周學習總結
第九章 虛擬儲存器
虛擬儲存器是計算機系統最重要的概念之一,它是對主存的一個抽象。
三個重要能力:
- 它將主存看成是一個儲存在磁碟上的地址空間的快取記憶體,在主存中只儲存活動區域,並根據需要在磁碟和主存之間來回傳送資料,通過這種方式,高效的使用了主存
- 它為每個程式提供了一致的地址空間,從而簡化了儲存器管理
- 它保護了每個程式的地址空間不被其他程式破壞
一、物理和虛擬定址
1.實體地址
- 計算機系統的主存被組織成一個由M個連續的位元組大小的單元組成的陣列,每位元組都有一個唯一的實體地址PA。
- 根據實體地址定址的是物理定址。
2.虛擬地址
- 虛擬儲存器被組織為一個由存放在磁碟上的N個連續的位元組大小的單元組成的陣列。
- 使用虛擬定址時,CPU通過生成一個虛擬地址VA來訪問主存,這個虛擬地址在被送到儲存器之前先轉換成適當的實體地址(這個過程叫做地址翻譯,相關硬體為儲存器管理單元MMU)
二、地址空間
1.地址空間
- 地址空間是一個非負整數地址的有序集合:{0,1,2,……}
2.線性地址空間 - 地址空間中的整數是連續的。
3.虛擬地址空間 - CPU從一個有 N=2^n 個地址的地址空間中生成虛擬地址,這個地址空間成為稱為虛擬地址空間。
4.地址空間的大小 - 由表示最大地址所需要的位數來描述。
- N=2^n:n位地址空間
三、虛擬儲存器作為快取的工具
- 虛擬儲存器——虛擬頁VP,每個虛擬頁大小為P=2^平位元組
- 物理儲存器——物理頁PP,也叫頁幀,大小也為P位元組。
- 任意時刻,虛擬頁面的集合都被分為三個不相交的子集:
未分配的:VM系統還沒分配/建立的頁,不佔用任何磁碟空間。
快取的:當前快取在物理儲存器中的已分配頁
未快取的:沒有快取在物理儲存器中的已分配頁
四、虛擬儲存器作為儲存器管理的工具
- 作業系統為每個程式提供了一個獨立的頁表,也就是一個獨立的虛擬地址空間。
- 抖個虛擬頁面可以對映到同一個共享物理頁面上。
- 儲存器對映:將一組連續的虛擬頁對映到任意一個檔案中的任意位置的表示法。
- VM簡化了連結和載入、程式碼和資料共享,以及應用程式的儲存器分配。
五、虛擬儲存器作為儲存器保護的工具
- PTE的三個許可位:
SUP:表示程式是否必須執行在核心模式下才能訪問該頁
READ:讀許可權
WRITE:寫許可權
六、地址翻譯
- 地址翻譯就是一個N元素的虛擬地址空間VAS中的元素和一個M元素的實體地址空間PAS中元素之間的對映。
- 頁面基址暫存器PTBR指向當前頁表。
- MMU利用VPN選擇適當的PTE。
- PPO=VPO。
1.結合快取記憶體和虛擬儲存器來看
首先,在既使用SRAM快取記憶體又使用虛擬儲存器的系統中,大多數系統選擇物理定址
主要思路是地址翻譯發生在快取記憶體之前
頁表目錄可以快取,就像其他的資料字一樣
2.利用TLB加速地址翻譯
步驟:
- CPU產生一個虛擬地址
- MMU從TLB中取出相應的PTE
- MMU將這個虛擬地址翻譯成一個實體地址,並且將它傳送到快取記憶體/主存
- 快取記憶體/主存將所請求的資料字返回給CPU
3.多級頁表
(1)以兩層頁表層次結構為例,好處是:
- 如果一級頁表中的一個PTE是空的,那麼相應的二級頁表就根本不會存在
- 只有一級頁表才需要總是在主存中,虛擬儲存器系統可以在需要時建立、頁面調入或調出二級頁表,只有最經常使用的二級頁表才快取在主存中。
(2)多級頁表的地址翻譯:
4.端對端的地址翻譯
七、案例研究
1.Core i7地址翻譯
- 在這裡,PTE有三個許可權位:
R/W位:確定內容是讀寫還是隻讀
U/S位:確定是否能在使用者模式訪問該頁
XD位:禁止執行位,64位系統中引入,可以用來禁止從某些儲存器頁取指令
- 還有連個缺頁處理程式涉及到的位:
A位,引用位,實現頁替換演算法
D位,髒位,告訴是否必須寫回犧牲頁
2.Linux虛擬儲存器系統
- Linux為每個程式維持了一個單獨的虛擬地址空間.
- 核心虛擬儲存器包括:核心中的程式碼和資料結構。
- 一部分割槽域對映到所有程式共享的物理頁面,另一部分包含每個程式都不相同的資料。
八、儲存器對映
- 即指Linux通過將一個虛擬儲存器區域與一個磁碟上的物件關聯起來,以初始化這個虛擬儲存器區域的內容的過程。
- 對映物件:
Unix檔案系統中的普通檔案
匿名檔案(全都是二進位制0)
1.共享物件和私有物件
(1)共享物件
- 共享物件對於所有把它對映到自己的虛擬儲存器程式來說都是可見的
- 即使對映到多個共享區域,物理儲存器中也只需要存放共享物件的一個拷貝。
(2)私有物件 - 私有物件運用的技術:寫時拷貝
- 在物理儲存器中只儲存有私有物件的一份拷貝
2.使用mmap函式的使用者級儲存器對映
(1)建立新的虛擬儲存器區域
#include <unistd.h>
#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
成功返回指向對映區域的指標,若出錯則為-1
引數含義:
- start:這個區域從start開始
- fd:檔案描述符
- length:連續的物件片大小
- offset:距檔案開始處的偏移量
- prot:訪問許可權位,具體如下:
PROT_EXEC:由可以被CPU執行的指令組成
PROT_READ:可讀
PROT_WRITE:可寫
PROT_NONE:不能被訪問
- flag:由描述被對映物件型別的位組成,具體如下:
MAP_ANON:匿名物件,虛擬頁面是二進位制0
MAP_PRIVATE:私有的、寫時拷貝的物件
MAP_SHARED:共享物件
(2)刪除虛擬儲存器:
include <sys/mman.h>
int munmap(void *start, size_t length);
成功返回0,失敗返回-1
- 從start開始刪除,由接下來length位元組組成的區域。
九、動態儲存器分配
- 堆:是一個請求二進位制0的區域,緊接在未初始化的bss區域後開始,並向上(更高的地址)生長。有一個變數brk指向堆的頂部
- 分配器的兩種基本風格:
顯示分配器-malloc和free
隱式分配器/垃圾收集器
1.malloc和free函式:
- 系統呼叫malloc函式,從堆中分配塊:
#include <stdlib.h>
void *malloc(size_t size);
- 成功返回指標,指向大小至少為size位元組的儲存器塊,失敗返回NULL
- 系統呼叫free函式來釋放已分配的堆塊:
#include <stdlib.h>
void free(void *ptr);
- 無返回值
- ptr引數必須指向一個從malloc、calloc或者reallov獲得的已分配塊的起始位置。
- 使用動態儲存器分配的原因:因為經常知道程式實際執行時,它們才知道某些資料結構的大小。
2.分配器的要求和目標:
- 要求
處理任意請求序列
立即響應請求
只使用堆
對齊塊
不修改已分配的塊
- 目標:
最大化吞吐率(吞吐率:每個單位時間裡完成的請求數)
最大化儲存器利用率——峰值利用率最大化
3.碎片
(1)內部碎片
- 發生在一個已分配塊比有效載荷大的時候
- 易於量化。
(2)外部碎片 - 發生在當空閒儲存器合計起來足夠滿足一個分配請求,但是沒有一個單獨的空間塊足以處理這個請求時發生
- 難以量化,不可預測。
4.隱式空閒連結串列
- 堆塊的格式:由一個字的頭部,有效荷載,和可能的額外填充組成。
- 空閒塊通過頭部中的大小欄位隱含地連線著,分配器可以通過遍歷堆中所有的塊,從而間接地遍歷整個空閒塊的集合。
- 系統對齊要求和分配器對塊格式的選擇會對分配器上的最小塊大小有強制的要求。
5.放置已分配的塊——放置策略
(1)首次適配
- 從頭開始搜尋空閒連結串列,選擇第一個合適的空閒塊
(2)下一次適配 - 從上一次搜尋的結束位置開始搜尋
(3)最佳適配 - 檢索每個空閒塊,選擇適合所需請求大小的最小空閒塊
6.申請額外的堆儲存器
用到sbrk函式:
#include <unistd.h>
vid *sbrk(intptr_t incr);
成功則返回舊的brk指標,出錯為-1
- 通過將核心的brk指標增加incr來擴充套件和收縮堆。
7.合併空閒塊
- 合併是針對於假碎片問題的,任何實際的分配器都必須合併相鄰的空閒塊。
- 有兩種策略:立即合併/推遲合併
8.顯式空閒連結串列
(1)區別
- 分配時間
隱式的,分配時間是塊總數的線性時間
顯式的,是空閒塊數量的線性時間。 - 連結串列形式
隱式——隱式空閒連結串列
顯式——雙向連結串列,有前驅和後繼,比頭部腳部好使。
(2)排序策略:
- 後進先出
按照地址順序維護
9.分離的空閒連結串列
分離儲存有兩種基本方法:
(1)簡單分離儲存
- 每個大小類的空閒連結串列包含大小相等的塊,每個塊的大小就是這個大小類中最大元素的大小。
- 如果連結串列非空:分配其中第一塊的全部
- 如果連結串列為空:分配器向作業系統請求一個固定大小的額外儲存器片,將這個片分成大小相等的塊,並且連線起來成為新的空閒連結串列。
- 優點:時間快,開銷小
- 缺點:容易造成內部、外部碎片
(2)分離適配
- 每個空閒連結串列是和一個大小類相關聯的,並且被組織成某種型別的顯示或隱式連結串列,每個連結串列包含潛在的大小不同的塊,這些塊的大小是大小類的成員。
- 這種方法快速並且對儲存器使用很有效率。
(3)夥伴系統——分離適配的特例
- 其中每個大小類都是2的冪。這樣,給定地址和塊的大小,很容易計算出它的夥伴的地址,也就是說:一個塊的地址和它的夥伴的地址只有一位不同。
- 優點:快速檢索,快速合併。
十、垃圾收集
- 垃圾收集器是一種動態儲存分配器,它自動釋放程式不再需要的已分配塊,這些塊被稱為垃圾,自動回收堆儲存的過程叫做垃圾收集。
(1)基本知識
- 垃圾收集器將儲存器視作一張有向可達圖,只有當存在一條從任意根節點出發併到達p的有向路徑時,才說節點p是可達的,而不可達點就是垃圾。
(2)Mark&Sweep垃圾收集器
- 有兩個階段:
標記:標記出根節點的所有可達的和已分配的後繼
清楚:釋放每個未被標記的已分配塊。
(3)C保守的Mark&Sweep——平衡二叉樹
- 根本原因是C語言不會用型別標記來標記儲存器位置。
十一、C程式中常見的與儲存器有關的錯誤
1.間接引用壞指標:常見錯誤:scanf錯誤
2.讀未初始化的儲存器:常見錯誤:假設堆儲存器被初始化為0
3.允許棧緩衝區溢位:常見錯誤:緩衝區溢位錯誤
4.假設指標和它們指向的物件是相同大小的:在遠處起作用action at distance
5.造成錯位錯誤
6.引用指標,而不是它所指向的物件
7.誤解指標運算
8.引用不存在的變數
9.引用空堆塊中的資料
10.引起儲存器洩露
學習總結
這周學習了教材的最後一章,至此,《深入理解計算機系統》這本教材就算告一段落了,但關於這方面的知識卻還有很多等著我們去發掘。我覺得這本教材編寫的特別棒,它把我學過的有關於作業系統、資料結構、組合語言以及C語言的很多東西都結合了起來,讓我對以前所學的知識有了一個全新的認知。
學習進度條
程式碼行數(新增/累積) | 部落格量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 0 | 2/2 | 20/20 | |
第二週 | 100/100 | 1/3 | 20/40 | |
第三週 | 200/300 | 1/4 | 22/62 | |
第五週 | 200/500 | 1/5 | 22/84 | |
第六週 | 274/774 | 1/6 | 22/106 | |
第七週 | 127/901 | 2/8 | 22/128 | |
第八週 | 50/951 | 2/10 | 22/150 | |
第九周 | 418/1369 | 2/12 | 22/172 | |
第十週 | 485/1854 | 2/14 | 22/194 | |
第十一週 | 628/2482 | 3/17 | 32/226 | |
第十二週 | 68/2550 | 2/19 | 32/258 | |
第十三週 | 423/2973 | 2/21 | 32/290 | |
第十四周 | 123/3096 | 2/23 | 32/322 |