首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

作業系統虛擬記憶體技術原理與OS161實戰代碼解析

     編輯:關於C語言

作業系統虛擬記憶體技術原理與OS161實戰代碼解析

虛擬記憶體是現代作業系統核心子系統,透過「邏輯位址空間與物理記憶體解耦」,實現進程隔離、記憶體共享、按需分頁等關鍵能力。本文從基本概念、頁式管理、TLB 加速、多級頁表到 Harvard OS161 真實內核代碼,層層深入剖析虛擬記憶體實現細節。

一、核心概念:位址空間 vs 儲存空間

  • 位址空間:編譯後目標程式所處的邏輯位址範圍,是邏輯位址的集合。
  • 儲存空間:主存中物理儲存單元的集合,單元編號稱為物理位址。
  • 頁/頁框:邏輯空間分固定大小的頁,物理空間分同樣大小的頁框,頁面大小通常 4KB。

二、頁式存儲管理與頁表機制

進程建立時,OS 為所有頁分配頁框;運行中動態申請空間時再分配。頁表項(PTE)記錄「虛擬頁號 → 物理頁框號」映射及權限位。但頁表駐留記憶體,每次記憶體訪問需兩次查表(查頁表 + 訪問資料),效率大幅下降。

三、TLB:翻譯後援緩衝器

TLB 是 MMU 內部的高速快取,儲存熱門頁表項。基於局部性原理,程式訪問臨近程式碼機率高,TLB 命中率可達 99%+,極大緩解「兩次訪問」問題。TLB 容量有限(典型 64-512 條),採用全相聯或組相聯映射。

四、二級頁表:壓縮頁表空間

32 位系統單級頁表需 4MB(1M 頁 × 4B),過大。二級頁表將頁號拆為「目錄索引 + 頁表索引」,一級頁表僅存儲二級頁表指標,未分配區域不分配二級頁表,大幅節省空間,代價是增加一次查表。

五、OS161 虛擬記憶體子系統代碼走讀

OS161 基於 MIPS-I,採用二級頁表,代碼倉庫:

https://github.com/tian-jiang/OS161-VirtualMemory

1. 記憶體佈局定義

/* arch/mips/include/vm.h */
#define MIPS_KUSEG 0x00000000  // 用戶空間,TLB 映射
#define MIPS_KSEG0 0x80000000  // 核心非快取映射
#define MIPS_KSEG1 0xa0000000  // 核心非快取非映射
#define MIPS_KSEG2 0xc0000000  // 核心 TLB 映射

2. 早期初始化:ram_bootstrap()

void ram_bootstrap(void) {
    size_t ramsize = mainbus_ramsize();
    if (ramsize > 508*1024*1024) ramsize = 508*1024*1024; // MIPS 限制
    lastpaddr = ramsize;
    firstpaddr = firstfree - MIPS_KSEG0; // firstfree 來自 start.S
    kprintf("%uk physical memory available\n", (lastpaddr-firstpaddr)/1024);
}

功能:探測物理記憶體大小,計算首個可用物理頁框 firstpaddr 與末尾 lastpaddr。

3. 幀表初始化:vm_bootstrap() → frametable_bootstrap()

void frametable_bootstrap(void) {
    paddr_t firsta, lasta;
    ram_getsize(&firsta, &lasta);           // 獲取可用物理範圍
    size_t framenum = (lasta - firsta) / PAGE_SIZE; // 總頁框數
    size_t frame_table_size = ROUNDUP(framenum * sizeof(struct frame_table_entry), PAGE_SIZE);
    size_t entry_num = frame_table_size / PAGE_SIZE; // 幀表自身佔用的頁數

    frametop = firsta;
    freeframe = firsta + frame_table_size; // 空閒頁框從幀表後開始
    frame_table = (struct frame_table_entry *)PADDR_TO_KVADDR(firsta); // 幀表置於物理記憶體起始處

    // 初始化空閒鏈表:前 entry_num 個項對應幀表自身,標記為已用
    for (i = 0; i < framenum-1; i++) {
        if (i < entry_num) { p->next_freeframe = 0; }
        else { p->next_freeframe = frametop + (i+1)*PAGE_SIZE; }
        p++;
    }
}

關鍵設計:幀表本身佔用物理記憶體起始區域,每項對應一個頁框,next_freeframe=0 表示已分配,非零指向下一個空閒頁框,形成單向鏈表。

4. 幀表項結構

struct frame_table_entry {
    size_t next_freeframe; // 下一個空閒頁框物理位址,0 表已分配
};

六、後續關鍵模組預覽

  • 頁面錯誤處理:缺頁中斷 → 分配物理頁框 → 讀入磁碟資料 → 更新頁表 → 重新執行指令。
  • 頁面置換算法:Clock / LRU / NFU 等,決定犧牲哪個頁框。
  • TLB 填充與撤銷:上下文切換時刷新 TLB,或使用 ASID 標識進程避免全刷。
  • 複製時寫:fork() 時共享頁框,寫入時才複製,優化進程創建效能。

七、總結

虛擬記憶體透過「分頁 + 頁表 + TLB + 多級頁表 + 頁面置換」協同工作,在有限物理記憶體上構建無限大的邏輯空間假象。OS161 代碼展示了教學級內核如何以清晰模組化方式實現這一複雜子系統,是理解作業系統記憶體管理的最佳實踐範本。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved