虛擬化與容器

影子分頁表(shadow page table)

影子分頁表(shadow page table)是針對虛擬化中一個棘手的「雙重轉譯」問題所提出的軟體解法。在一台虛擬機器裡,客體作業系統建立自己的分頁表,把客體虛擬位址轉譯成它以為的實體位址。但那些客體實體位址並非真的實體——它們只是超管理器發出的編號。於是有兩層轉譯:客體虛擬到客體實體(由客體管理),以及客體實體到真實機器實體(由超管理器管理)。真實硬體只跟著一組分頁表走,所以必須有東西把兩層合併。

影子分頁表用軟體做這個合併。對每個客體,超管理器暗中維護一組平行的分頁表——也就是「影子」——它一步就把客體虛擬位址一路對應到真實機器位址,把兩層合在一起。真實 CPU 被指向這些影子分頁表,而非客體自己的,所以位址轉譯能以完整的硬體速度進行。難處在於讓影子保持同步:每當客體編輯自己的分頁表,超管理器都必須察覺並更新對應的影子項目。它的做法是把客體的分頁表標記為唯讀,於是客體任何一次寫入都會陷入超管理器,由它把影子修補成一致。

在有硬體協助之前,影子分頁表就是記憶體虛擬化的運作方式,而且它能把轉譯做對——但每次客體更動分頁表都要陷入,代價高昂,對那些頻繁建立行程或更改對應的工作負載尤其如此。這份額外負擔,正是促成巢狀(延伸)分頁表的動機——由 CPU 自己同時走訪兩層,淘汰了大部分影子分頁表的記帳工作。影子分頁仍是說明「兩層位址問題」的乾淨範例,並在缺乏硬體巢狀分頁的場合出現。

一個客體行程觸碰到一個新的頁,客體核心更新自己的分頁表來記錄這個對應。因為超管理器把那張分頁表標記為唯讀,這次寫入會陷入;超管理器醒來,算出真實的機器頁框,把合併後的對應寫進影子分頁表,再讓客體繼續。

超管理器把兩層轉譯合併成一張真實 CPU 能用的影子分頁表。

影子分頁表正確卻昂貴,因為每一次客體分頁表的編輯都會陷入超管理器。巢狀(延伸)分頁表把那段兩層走訪搬進硬體,在 CPU 支援之處大致取代了影子分頁。

又稱
shadow paging影子分頁