之前頁表結構的不足
之前的頁表結構看起來挺好的呀,有什麼問題呢?
如果每個頁的大小是4k,也就是2的12次方。如果是32位的地址話,也就是說,有2的20次方個頁。
那麼對應到頁表,也就說頁表應該有2的20次方個項。因爲每個項表示的是一個內存地址,也就說一個項的大小是32位,也就是4個字節。
這樣算下來,對應於一個32位的內存地址,一個頁表應該4M大小。看起來還可以接受啊。
但注意,每個進程都有一個頁表。看下,我的電腦現在有280個進程,也就說如果採用之前的結構,光頁表結構就得佔用280*4M=1120M,大約1個G的大小。如果是64位系統,會更加可怕。
引入多級頁表
之前的一級頁表,我們對於32位系統,4k爲一頁的時候,我們如果要去訪問2的20次方的頁表,去查找空閒空間,或者訪問某一個頁內數據。
現在,我們採用多級頁表,如上圖所示的是二級頁表。
我們如果想訪問某一個地址,我們首先通過一個頁目錄號,在第一個頁表(頁目錄表)中獲得一個地址。這個地址指向第二個頁表的開始位置,然後用頁號作爲偏移,在第二個頁表中獲得地址,進而訪問內存中的塊。
想象這樣一個場景:如果,你現在有一本書,你想跳轉到某一頁。這本書每一頁都沒有頁碼,只有目錄有相關頁碼。
我們想要翻到的頁碼,提供這些信息:
- 它是屬於內存相關內容的
- 它在所在章節開始位置處的第60頁
於是,你打開了目錄,但是這個目錄也跟平時不一樣,它只有顯示每一章的頁碼,比如:第一章,進程,100頁;第二章,內存,200頁。沒有節的頁碼。
現在,我們想訪問的內容知道是屬於第二章的,於是我們直接來到第200頁。
(我們從頁目錄表來到了第二級頁表)。
最後我們從這個位置,往後找到第60頁的位置。
(從二級頁表偏移頁號找到對應的頁)
多級頁表的內存佔用
多級頁表的內存佔用和 頁目錄號、頁號的位數分配有關係。假定我們假設頁目錄號、頁號各佔10位。
在 Linux 0.11 中,頁目錄號是所有進程共享的,有的系統每個進程都有一個頁目錄號,當然也都有一個頁表。
所以,一個進程中有2的10次方(1K)的頁目錄表 和 2的10次方(1K)的頁號。因爲每個表項大小爲4字節,總共,一個進程才佔 8K 而已。比之前的 4M,大大節省了內存。
快表
至此,看起來,已經優化的差不多了。
但是,人們不止於此,想進一步提高性能。那麼如何提高性能呢?
緩存。
對於很多大量需要訪問的問題,都使用緩存,利用了程序的局部性原理。像我們的CPU的多級緩存都是使用這種原理。但是,一般緩存使用的寄存器價格都比較昂貴,所以一般存儲都有限。
快表,實質上也是緩存。
快表,TLB(translation lookasider buffer),翻譯後備緩衝器。
他就是保存最近的訪問的一些查表信息,如果有一個新的地址需要去訪問,先到 TLB 中看能不能找到,如果找不到,再按照之前的方式老老實實查詢,如果可以找到,直接返回結果。
更多細節,我們在後面講解。