操作系統 3.4-段頁結合的實際內存管理

段與頁結合的初步思路

  1. 虛擬內存的引入

    • 為了結合段和頁的優勢,操作系統引入了虛擬內存的概念。虛擬內存是一段地址空間,它映射到物理內存上,但對用戶程序是透明的。

  2. 段到虛擬內存的映射

    • 用戶程序中的段首先映射到虛擬內存的相應區域。這一步驟通過段表(Segment Table)實現,段表記錄了每個段的起始地址和長度。

  3. 虛擬內存到物理內存的映射

    • 虛擬內存中的區域再映射到物理內存的頁上。這一步驟通過頁表(Page Table)實現,頁表記錄了虛擬頁到物理頁框的映射關系。

  4. 地址翻譯

    • 用戶程序發出的地址首先被翻譯成虛擬地址,然后再翻譯成物理地址。這一過程通常由硬件中的內存管理單元(MMU)自動完成。

  5. 內存訪問

    • 一旦地址被翻譯成物理地址,CPU就可以訪問物理內存中的數據,執行指令或進行數據操作。

用戶從應用程序視角看待虛擬內存中的段和頁

從用戶程序的視角來看,虛擬內存中的段和頁提供了一種抽象的內存模型,使得程序能夠以一種簡化和統一的方式來訪問內存。以下是用戶程序如何查看和與虛擬內存中的段和頁交互的方式:

  1. 邏輯地址空間

    • 用戶程序操作的是邏輯地址空間,這是一個由操作系統管理的虛擬地址空間。在這個空間中,程序可以使用段和偏移量(如cs:ip)來訪問內存,而不需要關心物理內存的實際布局。

  2. 地址翻譯

    • 用戶程序發出的地址(如0x00345008)首先被翻譯成虛擬地址,然后再由操作系統和硬件(如內存管理單元MMU)翻譯成物理地址(如0x7008)。

    • 這個過程對用戶程序是透明的,用戶程序不需要知道具體的物理地址。

  3. 內存保護和隔離

    • 段和頁的結合允許操作系統實現內存保護和隔離。每個進程都有自己的虛擬地址空間,操作系統確保一個進程不能訪問另一個進程的內存空間。

  4. 虛擬內存的優勢

    • 虛擬內存提供了內存的抽象,使得程序可以假設它擁有一個連續的、大的內存空間,而實際上物理內存可能是分散的、有限的。

    • 這種抽象簡化了程序設計,提高了內存使用的靈活性,并允許操作系統更有效地管理內存資源。

重定位

邏輯地址到物理地址的轉換過程

  1. 邏輯地址:由段號和偏移量組成,例如 段號+偏移(cs:ip)

  2. 段表:包含段號、基址、長度和保護信息。

    • 段號:標識段的編號。

    • 基址:段在內存中的起始地址。

    • 長度:段的大小。

    • 保護:段的訪問權限(如只讀R、讀寫R/W)。

  3. 頁號和偏移:邏輯地址中的偏移量被進一步分解為頁號和頁內偏移。

  4. 頁表:包含頁框號和保護信息。

    • 頁框號:頁在內存中的物理位置。

    • 保護:頁的訪問權限(如只讀R、讀寫R/W)。

  5. 物理地址:由物理頁號和偏移量組成。

地址翻譯過程

  1. 邏輯地址:由段號和偏移量組成。

  2. 段表查找:根據段號查找段表,獲取基址和長度。

  3. 偏移分解:將偏移量分解為頁號和頁內偏移。

  4. 頁表查找:根據頁號查找頁表,獲取頁框號。

  5. 物理地址計算:將頁框號和頁內偏移組合成物理地址。

段頁同時存在的場景下,重定位過程是怎樣的

在斷頁同時存在的場景下,用戶發出的邏輯地址是CS加上段號和偏移量。

操作系統首先通過段表找到段在虛擬內存中的位置,并生成一個虛擬地址。

然而,這個虛擬地址并不是直接對應的物理內存地址,而是需要經過一次映射,根據虛擬地址計算出頁號,再結合頁內偏移得到物理地址。

最后,操作系統將這個物理地址發送到地址總線上,從而實現從段和頁兩個層次上的地址翻譯,確保代碼能夠正確執行和獲取數據。

一個實際的段頁結合的例子

內存分配

內存管理的核心

  • 內存管理核心就是內存分配:強調了內存分配是內存管理的關鍵部分。

具體示例

  • 指令_sum: .int 0 定義了一個名為 _sum 的變量,初始值為0。

  • 指令_main: mov [300], 0 將0移動到偏移量為300的地址。

  • 地址計算base + 300(offset) 表示將基地址和偏移量相加得到物理地址。

內存管理過程

  • 分配段、建段表:為進程分配內存段,并建立段表來管理這些段。

  • 分配頁、建頁表:為進程分配內存頁,并建立頁表來管理這些頁。

  • 進程帶動內存使用的圖譜:展示了進程如何使用內存的圖譜。

  • 從進程fork中的內存分配開始:說明了進程創建(fork)時的內存分配過程。

載入內存

程序加載過程

  1. 分配段:為程序的不同部分(如代碼、數據、棧)分配內存段。

  2. 建立段表:記錄每個段的基址、長度和保護屬性。

  3. 分配頁:將每個段進一步分為頁,并為每頁分配物理內存。

  4. 建立頁表:記錄每個頁的頁框號和保護屬性。

  5. 地址轉換:將程序中的邏輯地址轉換為物理地址,以便訪問實際的內存。

示例

  • 邏輯地址 0x300:表示用戶數據段中的一個地址。

  • 指令 _main: mov [300], 0:將0移動到偏移量為300的地址。

  • 段表和頁表:展示了如何通過段號和頁號查找對應的基址和頁框號,從而完成地址轉換。

分配虛擬內存,建立段表

從幻燈片中提取的代碼如下:

int copy_process(int nr, long ebp, ...)
{...copy_mem(nr, p); ...
}
?
int copy_mem(int nr, task_struct *p)
{unsigned long new_data_base;new_data_base = nr * 0x40000000; ?// 64M * nrset_base(p->ldt[1], new_data_base);set_base(p->ldt[2], new_data_base);
}
  1. 計算新的數據基址

    • copy_mem函數中,首先計算新的數據基址new_data_base。這個基址是通過將進程編號nr乘以0x40000000(即64MB)來得到的。這意味著每個進程將獲得64MB的虛擬內存空間。

  2. 設置段表

    • 使用set_base函數將計算出的新數據基址設置到進程的局部描述符表(LDT)中的相應段。在這個例子中,p->ldt[1]p->ldt[2]分別代表了兩個不同的段(例如,代碼段和數據段)。

    • set_base函數的作用是更新段描述符中的基址字段,使其指向新的虛擬內存區域。

  3. 進程控制塊(PCB)

    • task_struct *p是一個指向進程控制塊(PCB)的指針,它包含了進程的所有信息,包括段表。

    • 在進程創建時,操作系統會為新進程分配一個新的PCB,并復制父進程的相關信息,同時為新進程分配獨立的虛擬內存空間。

  4. 內存分配

    • 在Linux中,每個進程都有獨立的虛擬內存空間。通過fork()系統調用創建的新進程會繼承父進程的虛擬內存布局,但是操作系統會確保新進程的虛擬內存空間是獨立的,以防止進程間的相互干擾。

  5. 進程切換

    • 在進程切換時,操作系統需要更新CPU的段寄存器,以指向新進程的段表。這樣,當新進程開始執行時,它將在自己的虛擬內存空間中運行。

分配內存,建立頁表

這張幻燈片展示了在Linux操作系統中,如何為新創建的進程分配內存并建立頁表。以下是提取的代碼和對分配內存、建立頁表過程的總結:

提取的代碼

int copy_mem(int nr, task_struct *p)
{unsigned long old_data_base;old_data_base = get_base(current->ldt[2]);copy_page_tables(old_data_base, new_data_base, data_limit);
}
?
int copy_page_tables(unsigned long from, unsigned long to, long size)
{from_dir = (unsigned long *)(((from >> 20) & 0xffc));to_dir = (unsigned long *)(((to >> 20) & 0xffc));size = (unsigned long)((size + 0x3fffff) >> 22);for (; size-- > 0; from_dir++, to_dir++) {from_page_table = (0xfffff000 & *from_dir);to_page_table = get_free_page();// 這里應該還有代碼來復制頁表項和設置新的頁表}
}

分配內存、建立頁表的總結

  1. 獲取舊數據基址

    • copy_mem函數中,首先獲取當前進程的數據段基址(old_data_base,這通常是通過讀取當前進程的段表(LDT)來實現的。

  2. 調用復制頁表函數

    • 然后調用copy_page_tables函數,傳入舊數據基址、新數據基址(new_data_base)和數據段的大小(data_limit),以復制頁表

  3. 計算目錄基址

    • copy_page_tables函數中,計算源目錄(from_dir)和目標目錄(to_dir)的基址。這是通過將虛擬地址右移20位(即頁目錄的索引)并取低12位(頁目錄項的偏移)來實現的。

  4. 計算頁表項數量

    • 計算需要復制的頁表項數量(size),這是通過將數據段大小加上0x3FFFFF(即1MB-1,因為頁表項是按頁大小為單位的),然后右移22位(即頁大小為4KB)來實現的。

  5. 復制頁表項

    • 在循環中,對于每個頁表項,從源目錄讀取頁表項(from_page_table),然后從頁框(page frame)中獲取一個空閑頁(to_page_table = get_free_page())來存儲目標頁表項。

    • 這里應該還有代碼來復制頁表項的內容,并設置新的頁表項,包括頁框號、保護位等。

  6. 建立頁表

    • 通過上述步驟,為新進程建立了頁表,將虛擬地址映射到物理內存。

  7. 更新進程控制塊(PCB)

    • 最后,需要更新新進程的PCB,包括新的頁表基址等信息,以便新進程可以正確地訪問其虛擬內存。

from_dir,to_dir

from_dir = (unsigned long *)(((from >> 20) & 0xffc));
to_dir = (unsigned long *)(((to >> 20) & 0xffc));
size = (unsigned long)((size + 0x3fffff) >> 22);
?
for (; size-- > 0; from_dir++, to_dir++) {from_page_table = (0xfffff000 & *from_dir);// 這里應該還有代碼來復制頁表項和設置新的頁表
}
  1. 計算頁目錄地址

    • from_dirto_dir 是指向頁目錄的指針。它們是通過將虛擬地址右移20位(即頁目錄的索引)并取低12位(頁目錄項的偏移)來計算得到的。這是因為在x86架構中,頁目錄項是按4KB對齊的,所以需要取低12位來得到頁目錄項的偏移。

  2. 計算頁表項數量

    • size 是需要復制的頁表項數量。這是通過將數據段大小加上0x3FFFFF(即1MB-1,因為頁表項是按頁大小為單位的),然后右移22位(即頁大小為4KB)來計算得到的。

  3. 復制頁表項

    • 在循環中,對于每個頁表項,從源目錄讀取頁表項(from_page_table),然后從頁框(page frame)中獲取一個空閑頁(get_free_page())來存儲目標頁表項。

    • 這里應該還有代碼來復制頁表項的內容,并設置新的頁表項,包括頁框號、保護位等。

  4. 頁目錄指針

    • 頁目錄指針(CR3)用于指向當前進程的頁目錄。在進程切換時,需要更新CR3寄存器以指向新進程的頁目錄。

from_page_table,to_page_table

從幻燈片中提取的代碼和相關信息如下:

提取的代碼:

for (; size-- > 0; from_dir++, to_dir++) {to_page_table = get_free_page();*to_dir = ((unsigned long)to_page_table) | 7;
}
?
unsigned long get_free_page(void) {register unsigned long _res asm("ax");__asm__("std; repne; scasb\n\t""movl %%edx, %%eax\n\t""D"(mem_map+PAGING_END-1));return _res;
}

總結:

  1. 頁表復制過程

    • 在循環中,對于每個頁表項,首先通過調用get_free_page()函數為新進程分配一個空閑的頁框(物理內存頁)。

    • 然后,將新分配的頁框地址設置到目標頁目錄項中(to_dir),并設置頁表項的權限(這里通過或操作| 7來設置)。

  2. 頁表項權限設置

    • 在x86架構中,頁表項通常包含頁框號和一些權限位。這里的| 7操作可能是設置頁表項的權限位,例如可讀寫(RW)和存在位(P)。

  3. 頁表項結構

    • 幻燈片中展示了頁表項的結構,包括頁目錄號(10 bits)、頁號(10 bits)和偏移(12 bits)。這是x86架構中分頁機制的基本概念。

  4. 頁目錄和頁表

    • from_dirto_dir 分別指向源進程和目標進程的頁目錄項。通過復制頁目錄項,可以實現頁表的復制和更新。

  5. 獲取空閑頁框

    • get_free_page()函數通過匯編語言實現,用于掃描內存映射(mem_map)來找到一個空閑的頁框。這個過程涉及到檢查內存映射中的每個條目,直到找到一個空閑的頁框。

  6. 內存映射

    • mem_map是一個內存映射數組,用于跟蹤哪些頁框是空閑的,哪些已經被使用。PAGING_END可能是定義了內存映射數組的結束位置。

復制和更新頁表

這張幻燈片展示了在操作系統中,如何復制和更新頁表項以實現內存管理。以下是提取的代碼和對過程的總結:

提取的代碼:

for (; nr-- > 0; from_page_table++, to_page_table++) {this_page = *from_page_table;this_page &= ~2; // 只讀*to_page_table = this_page;*from_page_table = this_page;this_page -= LOW_MEM;this_page >>= 12;mem_map[this_page]++;
}

總結:

  1. 頁表項復制

    • 代碼中的循環遍歷所有的頁表項,從源頁表(from_page_table)復制到目標頁表(to_page_table)。

  2. 權限設置

    • this_page &= ~2; 這行代碼通過位操作清除頁表項中的某個權限位(通常是只讀位),確保復制的頁表項具有適當的權限設置。

  3. 頁表項更新

    • *to_page_table = this_page; 將修改后的頁表項寫入目標頁表。

    • *from_page_table = this_page; 也將修改后的頁表項寫回源頁表,這可能是為了確保源進程的頁表項也反映了權限的更改。

  4. 頁框號計算

    • this_page -= LOW_MEM; 這行代碼從頁框號中減去一個基址(LOW_MEM),可能是為了將頁框號轉換為相對于某個特定內存區域的偏移量。

  5. 頁框號轉換

    • this_page >>= 12; 這行代碼將頁框號右移12位,這通常是為了將頁框號轉換為頁框數組中的索引。

  6. 內存映射更新

    • mem_map[this_page]++; 這行代碼更新內存映射數組,增加對應頁框的使用計數。這是為了跟蹤每個頁框的使用情況,特別是在使用寫時復制(copy-on-write)技術時。

使用內存

寫時復制(COW)技術

寫時復制是一種優化技術,用于減少復制內存的開銷,特別是在創建新進程時。在寫時復制中,父子進程最初共享相同的物理內存頁,只有當進程實際修改內存頁時,才會創建該內存頁的副本。

幻燈片內容分析

  1. 內存共享與寫時復制

    • 只要段表和頁表設置正確,父子進程就可以通過MMU(內存管理單元)自動訪問相同的物理內存頁。

    • 當父子進程中的任何一個嘗試修改共享的內存頁時,操作系統會觸發寫時復制機制,為修改內存頁的進程創建一個新的物理內存頁副本

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/77603.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/77603.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/77603.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Amazon EC2】為何基于瀏覽器的EC2 Instance Connect 客戶端連接不上EC2實例

文章目錄 前言📖一、報錯先知?二、問題復現😯三、解決辦法🎲四、驗證結果👍五、參考鏈接🔗 前言📖 這篇文章將講述我在 Amazon EC2 上使用 RHEL9 AMI 時無法連接到 EC2 實例時所遇到的麻煩😖 …

Python學習筆記(二)(字符串)

文章目錄 編寫簡單的程序一、標識符 (Identifiers)及關鍵字命名規則:命名慣例:關鍵字 二、變量與賦值 (Variables & Assignment)變量定義:多重賦值:變量交換:(很方便喲) 三、輸入與輸出 (In…

Hydra Columnar:一個開源的PostgreSQL列式存儲引擎

Hydra Columnar 是一個 PostgreSQL 列式存儲插件,專為分析型(OLAP)工作負載設計,旨在提升大規模分析查詢和批量更新的效率。 Hydra Columnar 以擴展插件的方式提供,主要特點包括: 采用列式存儲&#xff0c…

es的告警信息

Elasticsearch(ES)是一個開源的分布式搜索和分析引擎,在運行過程中可能會產生多種告警信息,以提示用戶系統中存在的潛在問題或異常情況。以下是一些常見的 ES 告警信息及其含義和處理方法: 集群健康狀態告警 信息示例…

健康與好身體筆記

文章目錄 保證睡眠飯后百步走,活到九十九補充鈣質一副好腸胃肚子咕咕叫 健康和工作的取舍 以前對健康沒概念,但是隨著年齡增長,健康問題凸顯出來。 持續維護該文檔,健康是個永恒的話題。 保證睡眠 一是心態要好,沾枕…

vue實現在線進制轉換

vue實現在線進制轉換 主要功能包括: 1.支持2-36進制之間的轉換。 2.支持整數和浮點數的轉換。 3.輸入驗證(雖然可能存在不嚴格的情況)。 4.錯誤提示。 5.結果展示,包括大寫字母。 6.用戶友好的界面,包括下拉菜單、輸…

智體知識庫:poplang編程語言是什么?

問:poplang語言是什么 Poplang 語言簡介 Poplang(OPCode-Oriented Programming Language)是一種面向操作碼(Opcode)的輕量級編程語言,主要用于智體(Agent)系統中的自動化任務處理、…

二分查找5:852. 山脈數組的峰頂索引

鏈接:852. 山脈數組的峰頂索引 - 力扣(LeetCode) 題解: 事實證明,二分查找不局限于有序數組,非有序的數組也同樣適用 二分查找主要思想在于二段性,即將數組分為兩段。本體就可以將數組分為ar…

下列軟件包有未滿足的依賴關系: python3-catkin-pkg : 沖突: catkin 但是 0.8.10-

下列軟件包有未滿足的依賴關系: python3-catkin-pkg : 沖突: catkin 但是 0.8.10- 解決: 1. 確認當前的包狀態 首先,運行以下命令來查看當前安裝的catkin和python3-catkin-pkg版本,以及它們之間的依賴關系: dpkg -l | grep ca…

深度學習:AI 大模型時代的智能引擎

當 Deepspeek 以逼真到難辨真假的語音合成和視頻生成技術橫空出世,瞬間引發了全球對 AI 倫理與技術邊界的激烈討論。從偽造名人演講、制造虛假新聞,到影視行業的特效革新,這項技術以驚人的速度滲透進大眾視野。但在 Deepspeek 強大功能的背后…

醫學分割新標桿!雙路徑PGM-UNet:CNN+Mamba實現病灶毫厘級捕捉

一、引言:醫學圖像分割的挑戰與機遇 醫學圖像分割是輔助疾病診斷和治療規劃的關鍵技術,但傳統方法常受限于復雜病理特征和微小結構。現有深度學習模型(如CNN和Transformer)雖各有優勢,但CNN難以建模長距離依賴&…

CV - 目標檢測

物體檢測 目標檢測和圖片分類的區別: 圖像分類(Image Classification) 目的:圖像分類的目的是識別出圖像中主要物體的類別。它試圖回答“圖像是什么?”的問題。 輸出:通常輸出是一個標簽或一組概率值&am…

高并發秒殺系統設計:關鍵技術解析與典型陷阱規避

電商、在線票務等眾多互聯網業務場景中,高并發秒殺活動屢見不鮮。這類活動往往在短時間內會涌入海量的用戶請求,對系統架構的性能、穩定性和可用性提出了極高的挑戰。曾經,高并發秒殺架構設計讓許多開發者望而生畏,然而&#xff0…

藍橋杯--結束

沖刺題單 基礎 一、簡單模擬(循環數組日期進制) (一)日期模擬 知識點 1.把月份寫為數組,二月默認為28天。 2.寫一個判斷閏年的方法,然后循環年份的時候判斷并更新二月的天數 3.對于星期數的計算&#…

13、nRF52xx藍牙學習(GPIOTE組件方式的任務配置)

下面再來探討下驅動庫如何實現任務的配置,驅動庫的實現步驟應該和寄存器方式對應,關 鍵點就是如何調用驅動庫的函數。 本例里同樣的對比寄存器方式編寫兩路的 GPOITE 任務輸出,一路配置為輸出翻轉,一路設 置為輸出低電平。和 …

Java的基本語法(1)

一、運算符和表達式 舉例說明什么是運算符,什么是表達式: int a 1; int b 2; int c a b; 在這個例子當中,是運算符,并且是算術運算符 ab是表達式,因為是運算符,所以ab是算術表達式 1.1算術運算符 …

C++學習之密碼學知識

目錄 1.文檔介紹 2.知識點概述 3.項目準備 4.序列化介紹 5.項目中基礎組件介紹 6.基礎模塊在項目中作用 7.項目中其他模塊介紹 8.加密三要素 9.對稱加密和非堆成加密 10.對稱和非對稱加密特點 11.堆成加密算法des 12.des對稱加密算法 13.對稱加密算法aes 14.知識點…

安裝vllm

ubuntu 22.04, RTX3080, cuda 12.1, cudnn 8.9.7,cuda和cudnn的安裝參考:https://blog.csdn.net/m0_52111823/article/details/147154526?spm1001.2014.3001.5501。 查看版本對應關系,下載12.1對應的whl包,https://github.com/vl…

【WPF】自定義控件:ShellEditControl-同列單元格編輯支持文本框、下拉框和彈窗

需要實現表格同一列,單元格可以使用文本框直接輸入編輯、下拉框選擇和彈窗,文本框只能輸入數字,彈窗中的數據是若干位的二進制值。 本文提供了兩種實現單元格編輯狀態下,不同編輯控件的方法: 1、DataTrigger控制控件的…

Gson、Fastjson 和 Jackson 對比解析

目錄 1. Gson (Google) 基本介紹: 核心功能: 特點: 使用場景: 2. Fastjson (Alibaba) 基本介紹: 核心功能: 特點: 使用場景: 3. Jackson 基本介紹: 核心功能…