在作業系統中,記憶體管理可讓您以多種方法將部分記憶體分配給程序,並在不再需要時釋出記憶體供日後重複使用。現代作業系統使用位址空間隔離程序記憶體。
位址空間代表程序用來參照記憶體的一組虛擬位址。虛擬地址會直接對應到實際地址。Fuchsia 使用 VMAR (虛擬記憶體位址區域) 來代表位址空間。
VMAR、對應和 VMO
在 Fuchsia 中,每個程序都有根層級 VMAR,且可分區為 VMAR 和對應階層。對應點到基礎 VMO (虛擬記憶體物件):
VMAR 和 VM 對應
VMAR 是特定程序位址空間中的連續虛擬位址範圍:
- VMAR 可以為非重疊子區域含有子項 VMAR 和/或 VM 對應
- 這些限制會將防護位元套用至記憶體部分 (讀寫、執行檔等)
- 他們擁有子項的 WAVL 樹狀結構 可提高搜尋效率
VM 對應代表位址空間中的「對應」範圍,亦即由實體頁面支援的虛擬位址:
- VM 對應沒有子項
- 會對應 VMO 中的多個頁面
- 成功的網頁搜尋結束於此
以下是可用的 VMAR 和 VM 對應 syscall:
zx_vmar_allocate()
- 建立新的子項 VMARzx_vmar_map()
- 將 VMO 對應至程序zx_vmar_unmap()
- 從程序取消對應記憶體區域zx_vmar_protect()
- 調整記憶體存取權限zx_vmar_destroy()
- 刪除 VMAR 及其所有子項
另請參閱虛擬記憶體位址區域參考資料。
VMOS
VMO 是記憶體的位元組容器。這類頁麵包含實體頁面,可透過 VM 對應功能對應到位址空間。以下是 VMO 系統呼叫:
zx_vmo_create()
- 建立新的 VMOzx_vmo_create_child()
:建立新的子項 VMOzx_vmo_create_physical()
- 建立新的實體 VMOzx_vmo_get_size()
:取得 VMO 的大小zx_vmo_op_range()
:對 VMO 範圍執行作業zx_vmo_read()
- 從 VMO 讀取zx_vmo_replace_as_executable()
:製作 VMO 的可執行版本zx_vmo_set_cache_policy()
- 為 VMO 持有的網頁設定快取政策zx_vmo_set_size()
:調整 VMO 的大小zx_vmo_write()
- 寫入 VMO
另請參閱虛擬記憶體物件參考資料。
虛擬記憶體管理工具 (VMM)
虛擬記憶體管理工具 (VMM) 負責維護程序位址空間,包括:
- 提供指向對應虛擬位址範圍實體頁面的指標。
- 請確認位址範圍已設定正確的存取防護位元。
方法是管理 VMAR、VM 對應、VMO 與硬體頁面資料表之間的關係。另請參閱 VMM 原始碼。
程序開始時,其整個位址空間會表示為一個 VMAR。當位址空間的不同部分對應時,系統會填入 VMAR 階層樹狀結構。系統建立及刪除 VMAR 和 VM 對應時,會建立並刪除樹狀結構中的節點。
節點代表一個 VMAR 或 VM 對應:
- VMAR 會指向子項清單,其中其他 VMAR 和 VM 對應位於父項 VMAR 的位址範圍內。
- VM 對應會指向對應 VMO 中該位址範圍的範圍。
進一步瞭解如何透過根 VMAR 以視覺化方式呈現記憶體用量。
VMM 使用隨機位址空間版面配置隨機化機制,控管在位址空間中建立新 VMAR 的位址範圍。
aslr.entropy_bits
核心指令列選項可用來控管隨機化的熵長度。熵越高,剖析器位址空間就會變得越來越分散。
實體記憶體管理工具 (PMM)
實體記憶體管理工具 (PMM) 會將系統中的所有可用實體記憶體 (RAM) 彙整為頁面,並管理相關情況。負責在需要時提供免費的實體頁面給 VMO。
VMO 是要求分頁,系統會視需求填入 (承諾) 頁面。網頁在寫入時就會認可。在此之前,未提交的頁面會以單例實體的零頁面呈現。避免需要為未存取或僅限讀取的頁面分配記憶體。
另外,使用者空間分頁器也能為 VMO 提供支援,該頁面會視需求填入 VMO 中的特定內容,例如從磁碟中的檔案讀取的內容。瞭解如何撰寫使用者呼叫器。
範例:對應 VMO
如要對應 VMO:
請使用
zx_vmar_root_self()
取得程序根 VMAR 的控制代碼,例如:zx_handle_t vmar = zx_vmar_root_self();
使用
zx_vmo_create(...)
建立 VMO。這樣做會傳回 VMO 控制代碼,例如:const size_t map_size = zx_system_get_page_size(); zx_vmo_create(map_size, 0, &vmo);
使用
zx_vmar_allocate(...)
在父項 VMAR 中建立子項 VMAR。系統會傳回 VMAR 控制代碼和其起始位址,例如:const size_t region_size = zx_system_get_page_size() * 10; zx_vmar_allocate(vmar, ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE, 0, region_size, ®ion, ®ion_addr);
這是選擇性步驟,您也可以直接將 VMO 對應至父項。
使用
zx_vmar_map(...)
對應 VMAR 中的 VMO。這會傳回現在對應至 VMAR 的 VMO 起始位址,例如:zx_vmar_map(region, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, map_size, &map_addr);
範例:存取 VMO 對應
在上一個範例中,假設 zx_vmar_map()
傳回 map_addr
0x4000。如要存取對應的地址 0x4000,程式碼可能如下所示:
zx_vmar_map(...&addr); // addr = 0x4000
auto arr = reinterpret_cast<int*>(addr);
arr[0] = 1; // page fault
指標解除參照會導致頁面錯誤。如要解決頁面錯誤,核心會執行以下操作:
- 在從
root_vmar
開始,在程序的 VMAR 樹狀結構中搜尋位址 0x4000,直到找到包含該位址的 VM 對應為止。 - VM 對應會包含 VMO 參照,以及對應第一個位址的 VMO 頁面清單中的偏移值。查詢與位址 0x4000 對應的 VMO 偏移量。
- 如果 VMO 在該位移沒有頁面,請分配新的頁面。假設這個網頁的實際地址為 0xf000。
- 透過
ArchVmAspace
,將虛擬位址 0x4000 轉譯為硬體頁面資料表 0xf000。該資料表代表用於追蹤 MMU 所用實體位址對應的架構專屬頁面資料表。