Linux內核學習–內存尋址
內存地址
使用 x86 處理器時,需要區分三種地址:
- 邏輯地址(程序看到的地址):邏輯地址由一個段和偏移量組成。
- 線性地址(虛擬地址):位於邏輯地址和物理地址之間
- 物理地址:真實的地址,用於內存芯片級內存單元尋址
邏輯地址-->[分段單元]-->線性地址-->[分頁單元]-->物理地址
分段可以給每一個進程分配不同的線性空間地址,而分頁可以把同一線性空間映射到不同的物理空間
段寄存器
爲了快速地找到段選擇符,處理器提供了一些段寄存器
- cs:代碼段寄存器,指向包含程序指令的段。(另外包含有兩位的字段,用以指明CPU特權級)
- ss:棧寄存器,指向包含當前程序棧的段
- ds:數據段寄存器,指向包含靜態數據或者全局數據段
- es,fs,gs:作爲一般用途,指向任意數據段
硬件中的分頁
分頁單元把線性地址轉換爲物理地址。這個過程中有一個重要任務就是把請求的訪問類型與線性地址的訪問權限進行比較,如果內存訪問無效則產生缺頁異常。線性地址和物理地址都被分成固定大小的頁,通過頁表(存儲頁的對應關係)實現地址映射。
Linux採用多級分頁,即頁目錄表(可能多層)、頁表,每個頁目錄包含了若干下一級頁目錄地址…每個頁表包含若干物理內存。
頁表的一些字段:
- Present標誌:表示所指的頁是否在主存中。如果執行地址轉換時所需的頁表項對應的Present標誌爲0,則產生缺頁異常。
- Accessed標誌:用於確認該頁表是否被使用
- Dirty標誌:用於確認數據是否被修改
- Read/Write:用於確定該頁的權限,即可讀還是可寫
- User/Supervisor:用於確定用戶態是否可以訪問
高速緩存的寫操作
通過高速緩存可以大大節約CPU時間,更快地找到對應的物理地址。
對於寫操作,高速緩衝的兩種策略:
- write-through:控制器既寫RAM也寫高速緩存行,爲了提高寫的效率關閉告訴緩存。
- write-back:只更新高速緩存行,不改變RAM內容。當RAM必須被更新(例如在高速緩存上對應的數據要被移出時,或當一個FLUSH硬件信號產生),則寫回到RAM
write-back更加具有計算機一個非常重要的思想,我喜歡稱爲 懶處理,即不是必須則暫時不做。該思想在諸多地方均有體現,包括copy-on-write機制等。很多緩存都會這樣設置
TLB
用於加快線性地址轉換到物理地址。當進行查詢頁表之前,首先去TLB中查詢,TLB可以視爲一個寄存器,因此存儲內容較少但是查找速度極快,故將常用的頁表項存入TLB將大大加快地址轉換。 利用了局部性原理,即如果一個頁被訪問,則它之後可能很快又會被訪問。
因此平均每次地址轉換的時間爲:n*訪問TLB的時間+(1-n)*(訪問TLB的時間+訪問頁表的時間),n爲TLB的命中率
通常TLB的刷新的時機:改變內核頁表項、執行進程切換、創建新進程、釋放進程、處理缺頁異常時等