1. 程式人生 > >2017-2018-1 20155305 《信息安全系統設計基礎》第11周學習總結

2017-2018-1 20155305 《信息安全系統設計基礎》第11周學習總結

markdown 軟件工程師 處理程序 泄露 多看 c函數 虛擬 生成 緩存

2017-2018-1 20155305 《信息安全系統設計基礎》第11周學習總結

教材學習內容總結

地址

  • 物理和虛擬尋址 1、物理尋址 主存被組織成一個由M個連續的字節大小的單元組成的數組,依次類推的尋址方式。 技術分享圖片

2、虛擬尋址 CPU生成一個虛擬地址(VA)來訪問主存,在被傳送到存儲器之前先轉換成適當的物理地址。

技術分享圖片

地址翻譯通過CPU芯片上的存儲器管理單元完成。

  • 地址空間 一個非負整數地址的有序集合:{0,1,2,……}。 主存中的每個字節都有一個選自虛擬地址空間的虛擬地址和一個選自物理地址空間的物理地址。 1、線性地址空間 有序集合中整數是連續的。 2、虛擬地址空間 一個有 N=2n 個地址的地址空間,CPU從其中生成虛擬地址。 3、物理地址空間 與系統中的物理存儲器的M個字節相對應。 4、地址空間的大小 由表示最大地址所需要的位數來描述:N=2
    n:n位地址空間。

虛擬存儲器

  • 三個重要能力 它將主存看成是一個存儲在磁盤上的地址空間的高速緩存,在主存中只保存活動區域,並根據需要在磁盤和主存之間來回傳送數據,通過這種方式,高效的使用了主存 它為每個進程提供了一致的地址空間,從而簡化了存儲器管理 它保護了每個進程的地址空間不被其他進程破壞 作為緩存的工具 1、頁面 虛擬頁VP(虛擬存儲器),每個虛擬頁大小為P=2^平字節。 物理頁PP(物理存儲器),也叫頁幀,大小也為P字節。 任意時刻,虛擬頁面的集合都被分為三個不相交的子集:
未分配的:VM系統還沒分配、創建的頁,不占用任何磁盤空間。
緩存的:當前緩存在物理存儲器中的已分配頁。
未緩存的:沒有緩存在物理存儲器中的已分配頁。

2、頁表 一個數據結構,存放在物理存儲器中,將虛擬頁映射到物理頁。 (1)頁表就是一個頁表條目PTE的數組。 PTE:由一個有效位和一個n位地址字段組成的,表明了該虛擬頁是否被緩存在DRAM中。

PTE的三個許可位:

SUP:表示進程是否必須運行在內核模式下才能訪問該頁
READ:讀權限
WRITE:寫權限

(2)頁表的組成:有效位+n位地址字段 設置了有效位:地址字段表示DRAM中相應的物理頁的起始位置,這個物理頁中緩存了該虛擬頁。 沒有設置有效位: 空地址:表示該虛擬頁未被分配 不是空地址:這個地址指向該虛擬頁在磁盤上的起始位置。 3、缺頁 指DRAM緩存不命中。 缺頁異常:會調用內核中的缺頁異常處理程序,選擇一個犧牲頁。 頁面調度(交換):磁盤和存儲器之間傳送頁的活動。 按需頁面調度:直到發生不命中時才換入頁面的策略,所有現代系統都使用這個。 4、虛擬存儲器中的局部性 局部性原則:保證了在任意時刻,程序將往往在一個較小的活動頁面集合上工作,這個集合叫做工作集/常駐集。 顛簸:工作集大小超出了物理存儲器的大小。 只要程序有良好的時間局部性,虛擬存儲器系統就能工作的相當好。

  • 作為存儲器管理的工具 操作系統為每個進程提供了一個獨立的頁表,也就是一個獨立的虛擬地址空間。 存儲器映射:將一組連續的虛擬頁映射到任意一個文件中的任意位置的表示法。 多個虛擬頁面可以映射到同一個共享物理頁面上。 按需頁面調度和獨立的虛擬地址空間的結合簡化了鏈接和加載、代碼和數據共享,以及應用程序的存儲器分配。
  • 作為存儲器保護的工具 通過在PTE上添加一些額外的許可來控制對一個虛擬頁面的內容訪問。 地址翻譯 1、地址翻譯

技術分享圖片

一個N元素的虛擬地址空間VAS中的元素和一個M元素的物理地址空間PAS中元素之間的映射。

MAP: VAS → PAS ∪ ?

MAP = A‘ ,如果虛擬地址A處的數據在PAS的物理地址A‘處
MAP = ? ,如果虛擬地址A處的數據不在物理存儲器中

技術分享圖片

用頁表實現映射

技術分享圖片

  • 頁面命中時,CPU硬件執行步驟:
處理器生成虛擬地址,傳給MMU
MMU生成PTE地址,並從高速緩存/主存請求得到他
高速緩存/主存向MMU返回PTE
MMU構造物理地址,並把它傳給高速緩存/主存
高速緩存/主存返回所請求的數據給處理器。
  • 處理缺頁時,CPU硬件執行步驟
處理器生成虛擬地址,傳給MMU
MMU生成PTE地址,並從高速緩存/主存請求得到他
高速緩存/主存向MMU返回PTE
PTE中有效位為0,觸發缺頁異常
確定犧牲頁
調入新頁面,更新PTE
返回原來的進程,再次執行導致缺頁的指令,會命中

2、結合高速緩存和虛擬存儲器 在既使用SRAM高速緩存又使用虛擬存儲器的系統中,大多數系統選擇物理尋址。 兩者結合的主要思路是地址翻譯發生在高速緩存之前。 頁表目錄可以緩存,就像其他的數據字一樣。 3、利用TLB加速地址翻譯 TLB:翻譯後備緩沖器,是一個小的、虛擬存儲的緩存,其中每一行都保存著一個由單個PTE組成的塊。 步驟:

CPU產生一個虛擬地址
MMU從TLB中取出相應的PTE
MMU將這個虛擬地址翻譯成一個物理地址,並且將它發送到高速緩存/主存
高速緩存/主存將所請求的數據字返回給CPU

4、多級頁表 采用層次結構,用來壓縮頁表。 好處:

  • 如果一級頁表中的一個PTE是空的,那麽相應的二級頁表就根本不會存在。
  • 只有一級頁表才需要總是在主存中,虛擬存儲器系統可以在需要時創建、頁面調入或調出二級頁表,只有最經常使用的二級頁表才緩存在主存中。 地址翻譯:

技術分享圖片

案例研究

  • core i7地址翻譯 PTE的三個權限位:
        R/W位:確定內容是讀寫還是只讀
        U/S位:確定是否能在用戶模式訪問該頁
        XD位:禁止執行位,64位系統中引入,可以用來禁止從某些存儲器頁取指令

1、linux為每個進程維持了一個單獨的虛擬地址空間,其中,內核虛擬存儲器位於用戶棧之上。 內核虛擬存儲器包含內核中的代碼和數據結構,還有一些被映射到一組連續的物理頁面(主要是便捷地訪問特定位置,比如執行I/O操作的時候需要的位置)。 2、linux將虛擬存儲器組織成一些區域(也叫做段)的集合。 允許虛擬地址空間有間隙;內核不用記錄那些不存在的頁,這樣的頁也不用占用存儲器。 區域結構:

vm _start:指向這個區域的起始處;
vm _end:指向這個區域的結束處;
vm _prot:描述這個區域內所包含的所有頁的讀寫許可權限; 
vm _fags:描述這個區域內的頁面是與其他進程共享的,還是這個進程私有的,等等;
vm _next:指向鏈表的下一個結構.

存儲器

  • 存儲器映射 Linux通過將一個虛擬存儲器區域與一個磁盤上的對象關聯起來,以初始化這個虛擬存儲器區域的內容的過程。 映射對象:
Unix文件系統中的普通文件
匿名文件(全都是二進制0)

1、共享對象 對於所有把它映射到自己的虛擬存儲器進程來說都是可見的。即使映射到多個共享區域,物理存儲器中也只需要存放共享對象的一個拷貝。 2、私有對象 運用寫時拷貝的技術,在物理存儲器中只保存有私有對象的一份拷貝。 3、fork函數:應用了寫時拷貝技術。為每個進程保持了私有地址空間的抽象概念。 4、execve函數:將程序加載到存儲器。 Execve("a.out",NULL,NULL); 步驟:

刪除已存在的用戶區域。 
映射私有區域。 
映射共享區域。 
設置程序計數器。

5、map函數: (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

(2)刪除虛擬存儲器

#include <sys/mman.h>、

int munmap(void *start, size_t length);
//成功返回0,失敗返回-1

從start開始刪除,由接下來length字節組成的區域。

  • 動態存儲器分配 堆:一個請求二進制0的區域,緊接在未初始化的bss區域後開始,並向上(更高的地址)生長。有一個變量brk指向堆的頂部。 使用動態存儲器分配原因:經常直到程序實際運行時,才知道某些數據結構的大小。 分配器的兩種基本風格:
顯示分配器-malloc和free
隱式分配器/垃圾收集器

1、malloc函數:從堆中分配塊。

#include <stdlib.h>

void *malloc(size_t size);
//成功返回指針,指向大小至少為size字節的存儲器塊,失敗返回NULL

2、free函數:釋放已分配的堆塊。

#include <stdlib.h>

void free(void *ptr);
//無返回值,ptr參數必須指向一個從malloc、calloc或者reallov獲得的已分配塊的起始位置。

3、分配器的要求和目標 要求:

處理任意請求序列
立即響應請求
只使用堆
對齊塊
不修改已分配的塊

目標:

最大化吞吐率
最大化存儲器利用率——峰值利用率最大化

4、碎片:雖然有未使用的存儲器,但是不能用來滿足分配請求。

  • 內部碎片:發生在一個已分配塊比有效載荷大的時候,易於量化。
  • 外部碎片:發生在當空閑存儲器合計起來足夠滿足一個分配請求,但是沒有一個單獨的空間塊足以處理這個請求時發生。難以量化,不可預測。 5、隱式空閑鏈表 將堆組織成一個連續的已分配塊和空閑塊的序列:空閑塊通過頭部中的大小字段隱含地連接著,分配器可以通過遍歷堆中所有的塊,從而間接地遍歷整個空閑塊的集合。 需要特殊標記的結束塊。 6、放置策略:放置已分配的塊。
  • 首次適配:從頭開始搜索空閑鏈表,選擇第一個合適的空閑塊
  • 下一次適配:從上一次搜索的結束位置開始搜索
  • 最佳適配:檢索每個空閑塊,選擇適合所需請求大小的最小空閑塊 7、申請額外的堆存儲器
#include <unistd.h>

vid *sbrk(intptr_t incr);
//成功則返回舊的brk指針,出錯為-1  

通過將內核的brk指針增加incr來擴展和收縮堆。 8、合並空閑塊 合並是針對於假碎片問題的,任何實際的分配器都必須合並相鄰的空閑塊。 策略:

立即合並
推遲合並

  • 垃圾收集

垃圾收集器是一種動態存儲分配器,自動釋放程序已經不再需要的已分配塊(垃圾)。 垃圾收集器將存儲器視為一張有向可達圖,圖的節點被分配為一組根節點和一組堆節點。 1、Mark&Sweep垃圾收集器 由標記階段和清除階段組成,標記階段標記出根節點所有可達的和已分配的後繼,清除階段釋放每個未被標記的已分配塊。

C程序中常見的與存儲器有關的錯誤

  • 間接引用壞指針 在進程的虛擬地址空間中有較大的洞,沒有映射到任何有意義的數據,如果試圖引用一個指向這些洞的指針,操作系統就會以段異常來終止程序。 典型的錯誤:scanf("%d",val);
  • 讀未初始化的存儲器 bass存儲器位置總是被加載器初始化為0,但對於堆存儲器卻並不是這樣的。 典型的錯誤:假設堆存儲器被初始化為0。
  • 允許棧緩沖區溢出 如果一個程序不檢查輸入串的大小就寫入棧中的目標緩沖區,程序就會出現緩沖區溢出錯誤。
  • 假設指針和指向他們的對象大小是相同的
  • 造成錯位錯誤 一種很常見的覆蓋錯誤來源。
  • 引用指針,而不是他所指向的對象 註意C的優先級和結合性。
  • 誤解指針運算 忘記了指針的算術操作是以它們指向的對象的大小為單位來進行,而這種大小單位不一定是字節。
  • 引用不存在的變量 不理解棧的規則,有時會引用不再合法的本地變量。
  • 引用空閑堆塊中的數據
  • 引起存儲器泄露 當不小心忘記釋放已分配塊,而在堆裏創建了垃圾時,就會引起存儲器泄露。

其他(感悟、思考等,可選)

本周學習的主要內容是存儲器,從本章中,我鞏固了之前在其他課中學習的一些知識,如:虛擬地址、尋址方式、缺頁置換等,也學習了一些新的知識,如:LINUX 虛擬存儲器系統、動態存儲器分配、垃圾收集等,將不同課程的知識結合起來,融會貫通,有利於我們構建完整的知識體系、將知識活學活用,而不是單純的背、記,只是為了應付考試。

本周結對學習情況

- [20155311](博客鏈接)
- 結對照片
- 結對學習內容
    -存儲器技術,緩存,局部性
    
   

學習進度條

代碼行數(新增/累積) 博客量(新增/累積) 學習時間(新增/累積) 重要成長
目標 5000行 30篇 400小時
第一周 10/ 10 1/1 10/10
第三周 158/ 168 1/2 17/27
第五周 145/ 313 3/ 5 21/48
第六周 209/ 522 1/ 6 20/68
第七周 200/ 722 2/ 8 20/88
第九周 55/ 777 2/ 10 19/107
第十一周 11/ 788 2/ 12 18/125

嘗試一下記錄「計劃學習時間」和「實際學習時間」,到期末看看能不能改進自己的計劃能力。這個工作學習中很重要,也很有用。 耗時估計的公式 :Y=X+X/N ,Y=X-X/N,訓練次數多了,X、Y就接近了。

參考:軟件工程軟件的估計為什麽這麽難,軟件工程 估計方法

  • 計劃學習時間:20小時

  • 實際學習時間:19小時

  • 改進情況:開始進入學習狀態,但因為別的課程作業也很多,所以安排不夠好,可能學習不夠認真

(有空多看看現代軟件工程 課件 軟件工程師能力自我評價表)

2017-2018-1 20155305 《信息安全系統設計基礎》第11周學習總結