1. 程式人生 > >Virtual Memory(虛擬記憶體)

Virtual Memory(虛擬記憶體)

18-600快要考試了,在部落格中把學過的東西整理一下思路,寫到部落格裡也好以後自己有空看看,希望對以後的人也有所幫助。至於這門課的Lab的程式碼,等我考完試就把它放上來。

本次複習的重點如下:

這裡寫圖片描述

我感覺考試的重點就是都是重點,23333~ 話不多說,今天就開始講我最不熟悉的部分:虛擬記憶體(Virtual Memory)。

在鄙人的印象中,CPU和儲存器之前是通過匯流排連線,根據某些協議進行通訊,I2C,或者別的什麼協議的。在進行資料傳遞的時候,就需要傳遞地址。我覺得傳遞的就是直接的實體地址,如下圖:

這裡寫圖片描述
想起那個時候寫HDL的Cache都是這麼來的。

但是我在上課的時候,我發現我理解錯了。其實CPU發給Memory的是虛擬地址、Memory接到的是實體地址、它們之間有一個叫做MMU的東西。就是把虛擬地址轉換成實體地址,再進行資料的傳遞。如下圖所示:

這裡寫圖片描述

從這裡我們可以看出,從VA到PA之間其實是有一個對映函式在這裡面,把VA對映到PA。那麼這裡我們就要提問題了,為什麼要加VA呢?怎麼對映的呢?

首先回答第一個問題:Why VM?

Why VM?

看解釋。
這裡寫圖片描述
第一個是說可以通過VM,使得DRAM成為VAP的一部分。一般來說呢,VA的地址空間比PA大很多,這裡的實體地址是Cache或者是DRAM。

在最早的儲存金字塔我們可以知道DRAM不命中的後果是比SRAM嚴重得多,差不多是4個數量級的差別。所以我們需要儘可能增加DRAM的命中率。在物理級別,DRAM其實可以看做是磁碟的Cache。那麼我們在這裡採取VM,其實可以看成是磁碟的一種地址對映。從更高的維度去獲取DRAM的資料,可以非常靈活,比如VM中的虛擬頁可以對映到任何一個DRAM中的物理頁。如果排程合理的話,將可以極大降低MISS。

在這裡,為了使得VM和PM之間的資料對映更加靈活,採取了一種分頁的方法。這種方法把VM和PM分成固定大小的頁,這些頁形成了一種叫做頁表的東西。如果頁的大小不一樣的話,那麼做對映的時候其實會更復雜一些。我覺得如果頁的大小可以隨機變化的話,一方面是增加了維護成本,複雜度等等;但是另外一方面我覺得如果可以頁的大小自己設定的話,那麼就可以計算當前執行程式的一個working set,把需要的頁面載入進去PM,增加Hit的概率,減小Miss。在這裡呢,需要額外說一下工作集:就是程式執行時的較小的活動頁面。如果在工作集裡執行,那麼Hit非常高。否則就會有顛簸,頁面會頻繁地page in and out。

這裡寫圖片描述

頁表包含了VP和PP的對映關係。通過頁表這樣的一個對映,那麼VM和PM就聯絡了起來。頁表中每一項都有一個地址和它的值。它的地址當然就是對應VP(虛擬頁面),儲存的值就是PPN。

比如現在CPU傳了一個虛擬地址,然後虛擬地址就找到對應頁表中的PPN(物理頁號),然後在由虛擬地址和物理頁號找到最終的實體地址。如果沒有找到的話,就需要在PM載入所需要的頁,再增加到PT。再執行一次剛才的請求。怎麼樣確定所需要的頁呢?(等我學了神課Operating System再說)在這裡,我只是一筆帶過地址翻譯,具體的涉及到了MMU、TLB的細節的請看下面的VM Translation。

現在我們來說說VM的第二個作用:儲存器管理。
每個程序都有自己的虛擬地址空間,它們自己的虛擬地址空間可以任意對映到實體地址空間。那麼這樣你可以發現不少好處,比如簡化連結,在我們的進行連結的時候,每個程序都可以從自己空間的同一個地址開始載入,當然它們外面有一個基地址作為區別。這樣的話,程序載入就可以從自己的虛擬地址空間的同一個起始地址開始,大大降低了連結的難度。另外呢,我們進行資料共享的時候更方便,想想如果沒有VM,所有的資料直接引用DRAM裡面,然後好幾個程序引用同一個物理頁,那麼引用的時侯地址都是不連續的。不像VM一樣,在程式設計師角度看來地址都是連續的。不連續的話就會導致跳轉增加,而且容易導致程式混亂,不方便管理。還有就是採用分頁呢可以方便記憶體管理,寫過Malloc的同學應該都瞭解外部碎片,那麼採用了分頁呢,可以減少外部碎片。然後使用VM呢,可以使得Malloc記憶體的時候,不一定需要連續的記憶體,可以對映到K個任意頁面。這樣也是減少了外部碎片。

第三個作用就是作為儲存器保護工具。具體的就是在每個虛擬頁之前加入訪問許可權,其實就是加入了幾個bits(SUP、READ、WRITE、EXEC)。其實我覺得這個功能說起來有點兒牽強,其實在PM裡同樣也可以這麼加。我看不出在VM加如這個就能有這個特殊性。

這裡寫圖片描述

通過以上介紹,VM確實有很多好處,當然也必須看到它所帶來的一些Memory的cost,以及為了維護PT、地址翻譯等等需要不少的額外。

其實VM我覺得還有一個好處,它可以使得一個很大的儲存器(比如很多磁碟的組合)協同工作。通過VM可以使得很多的細節被掩藏了起來,我們不需要知道背後的記憶體系統。我們只需要對於VM進行操作即可。

雖然剛剛說我們程式設計不需要對VM背後的記憶體系統進行了解,但是對於地址翻譯這個,我覺得說一下還是有好處的。

VM Translation

地址翻譯:把虛擬地址對映成實體地址。也就是給你一個虛擬地址,對映關係(頁表),你得知道它的實體地址。

首先,瞭解一些基本概念。
這裡寫圖片描述

然後我來說一下地址翻譯的過程。

首先是邏輯層面
這裡寫圖片描述
上圖中就是說給了一個虛擬地址(VPN+VPO),根據VPN,去找到頁表的相應PPN。如果invalid,那麼就先載入這一頁到PM,再更新PTE。

硬體層面,CPU發虛擬地址給MMU,MMU解析出虛擬頁號,然後傳送給Cache/DRAM。然後在Cache中存著頁表,找到之後發回給MMU。如果沒找到,就從磁碟中載入。在這之後,MMU把虛擬地址的offset和Cache發給MMU的物理頁號合併之後發給Cache,Cache把資料取出,發給了CPU。
命中->
這裡寫圖片描述

缺頁->
這裡寫圖片描述

聰明的你應該發現了MMU為了獲取物理頁號和Cache/memory有一個通訊,這是比較消耗cycle的。所以就有了TLB(Translation lookaside buffer),是由VPN、PPN、valid bit組成。其實我覺得它就是page table的一個cache。TLB和VPN、PTE的關係:把虛擬地址的虛擬頁號分成TLBT、TLBI。VPO就是PPO。

這裡寫圖片描述

在增加了TLB之後的page hit和page fault的情況。

page hit->
這裡寫圖片描述
page fault->
這裡寫圖片描述

在使用了TLB之後,我們可以加速Address Translation。但是我們遇到了另外一個問題:採取單級PT會使得PT的大小就非常大。那麼就有了MPT。這種思路就可以讓我們把需要的大頁面載入到記憶體中,這裡已經有了partition的思想在裡面。
這裡寫圖片描述

接下來舉一個具體的例子,看一下虛擬地址是如何從VA、TLB、PT、PA這個心路歷程。
1、虛擬地址和實體地址的表示:14位的虛擬地址,12位的實體地址。頁大小是64bytes。那麼計算得出offset就需要6個bits。那麼剩下的VPN就是8bits。
這裡寫圖片描述
2、TLB的組成:4組4路的Cache。因為是4組,那麼就需要2bit做索引。剩下的6個bits那麼就是tag了。
這裡寫圖片描述
3、頁表:因為虛擬頁號是8 bits,那麼就可以用256個頁。我們只看前16個頁(主要是為了做題)
這裡寫圖片描述
4、PM中的Cache:
這裡寫圖片描述
以上的PPT裡面就有一個例子,給出了VPN,它是如何從TLB取出所需的值。然後如果TLB miss的話,就從PT取出值。如果PT miss的話,就從Cache/DRAM調入新的頁面。更新PT、TLB。

Some tips

1、定址方式:位元組定址
2、在換頁的時候採用的是write back的方式。
3、page fault的情況:invalid和access deny
這裡寫圖片描述

以上PPT的截圖來自於課程CMU15-213的主頁:CMU 15-213主要是這門課還是CSAPP的作者講的。

其實我在上的是CMU 18-600,如果你想了解更多關於處理器比如Superscala的東西的話,請看:CMU 18-600 其中講課的人還有一個是我的導師,在做處理器方面很牛逼的老師。