| RFC-0280:VMO 參考資料和切片歸因 | |
|---|---|
| 狀態 | 已接受 |
| 區域 |
|
| 說明 | 建議變更 VMO 參照和切片子項的記憶體歸因。 |
| 問題 | |
| Gerrit 變更 | |
| 作者 | |
| 審查人員 | |
| 提交日期 (年-月-日) | 2026-03-31 |
| 審查日期 (年-月-日) | 2026-03-31 |
問題陳述
參照和切片是 VMO 子項類型,會將讀取和寫入等作業轉送至父項 VMO。作業的行為就像是在父項 VMO 的重複控制代碼上執行一樣。
目前,使用 zx_object_get_info 查詢時,參照和切片報表會針對所有欄位回報零個歸因位元組。
此外,您無法查詢 VMO 是否為參照或切片,因此難以判斷零個歸因位元組是否代表沒有內容。API 使用者會依賴駭客偵測及歸因這些複製類型。
這項計畫造成了一些問題。
Fxfs
Fxfs 會使用參照,將控制代碼發給 Blob 和可變動檔案。這會造成問題,因為使用現有 API 時,無法擷取檔案保持開啟狀態的用戶端相關資訊。為 fxfs 歸因時,記憶體監控器目前會採用一種變通做法,將總位元組為 0 的所有 VMO 視為參照。
IOBuffers
IOBuffers 會使用參照,追蹤端點上的對等互連。在 IOBuffer 實作中,根 VMO 位於核心,因此無法從使用者空間查詢屬性。這個案例也包含巢狀參照,這會使情況更加複雜。
孤立記憶體
如果 VMO 只有參照和切片副本,且遭到捨棄,原始 VMO 的 VmCowPages 會保持存留,但這些頁面不會歸給任何 VMO。由於 API 限制,記憶體監控器無法擷取原始 VMO 或其複製項的任何資訊,因此會將此視為「孤立記憶體」。
摘要
這項 RFC 建議透過 zx_object_get_info 變更 VMO 參照和切片子項的記憶體屬性。參考和切片子項現在會回報記憶體,就好像查詢是在父項上執行一樣。只有在可見範圍內的位元組,才會回報給切片。
此外,zx_info_vmo::flags 會新增兩個標記,讓使用者查詢 VMO 是否為參照 ZX_INFO_IS_REFERENCE 或切片 ZX_INFO_VMO_IS_SLICE。
這些異動應可為 API 使用者提供足夠資訊,方便他們自行管理參照出處。
利害關係人
協助人員:
jamesr@google.com
審查者:
etiennej@google.com、rashaeqbal@google.com
已諮詢:
adanis@google.com
公共平台:
我們已將文件傳送至 fuchsia-memory-wg 和 zircon-discuss 郵寄清單,徵求意見。這份文件列出現有歸因機制的問題、建議解決方案,以及考慮採用的替代解決方案。
需求條件
為了讓記憶體監控和一般記憶體會計功能正常運作 (包括模擬 Linux 記憶體歸因 API),您應該還是可以根據 zx_info_vmo_t 中提供的資訊計算這些標準指標:
- 記憶體總量 (相當於 RSS/常駐集大小)
- 「這個 VMO 參照的記憶體總量」
- 私有記憶體 (相當於 USS/不重複集合大小)
- 「如果這個 VMO 遭到破壞,將釋放的記憶體」
- 縮放記憶體 (相當於 PSS/比例集大小)
- 「這個 VMO 占總記憶體量的比例」
- 總和必須等於系統記憶體總用量
設計
從 zx_object_get_info 傳回的歸因資訊會變更,因此參照和切片會將位元組回報為父項。系統會在 zx_info_vmo::flags 中新增兩個旗標,讓使用者查詢 VMO 是否為參照 ZX_INFO_IS_REFERENCE 或切片 ZX_INFO_VMO_IS_SLICE。
API 使用者可據此決定如何將位元組歸因於參照。系統可能會回報總記憶體,就好像參照是父項一樣。新標記可用於傳回私有記憶體的 0,並正確計算總記憶體。
參考範例
以參照為例,假設 VMO 有兩個已提交的頁面和一個參照子項,歸因變更如下。假設頁面大小為 4096,API 查詢的變更方式如下:
現有歸因:
zx_info_vmo_t info;
reference.get_info(ZX_INFO_VMO, &info, sizeof(info), nullptr, nullptr)
info.committed_bytes = 0
info.populated_bytes = 0
info.committed_private_bytes = 0
info.populated_private_bytes = 0
info.committed_scaled_bytes = 0
info.populated_scaled_bytes = 0
info.committed_fractional_scaled_bytes = 0
info.populated_fractional_scaled_bytes = 0
建議的歸因:
zx_info_vmo_t info;
reference.get_info(ZX_INFO_VMO, &info, sizeof(info), nullptr, nullptr)
info.committed_bytes = 8192
info.populated_bytes = 8192
info.committed_private_bytes = 8192
info.populated_private_bytes = 8192
info.committed_scaled_bytes = 8192
info.populated_scaled_bytes = 8192
info.committed_fractional_scaled_bytes = 0
info.populated_fractional_scaled_bytes = 0
info.flags & ZX_INFO_IS_REFERENCE = true;
info.flags & ZX_INFO_IS_SLICE = false;
切片範例
假設我們有一個 VMO,其中有兩個已提交的頁面,且每個頁面都有一個切片,則在頁面大小為 4096 的情況下,新版 API 會回報以下歸因。系統會將其視為在父項上查詢歸因,範圍是切片可見的範圍。
建議的歸因:
zx_info_vmo_t info;
slice.get_info(ZX_INFO_VMO, &info, sizeof(info), nullptr, nullptr)
info.committed_bytes = 4096
info.populated_bytes = 4096
info.committed_private_bytes = 4096
info.populated_private_bytes = 4096
info.committed_scaled_bytes = 4096
info.populated_scaled_bytes = 4096
info.committed_fractional_scaled_bytes = 0
info.populated_fractional_scaled_bytes = 0
info.flags & ZX_INFO_IS_REFERENCE = false;
info.flags & ZX_INFO_IS_SLICE = true;
實作
這項變更的 Kernel 實作方式很簡單,但需要與記憶體監控器協調,確保不會從參照和切片回報錯誤值。
效能
這項變更會導入 cow-pages 樹狀結構的逐步升級,否則我們會傳回零,因此查詢某些參照時,zx_object_get_info 可能會變慢。
安全性考量
查詢「*_scaled」欄位或比較私人位元與非私人位元時,可能會推斷出原始 VMO 的寫入時複製複製項相關旁路資訊,這在舊版歸因機制中是不可能發生的。這不會對目前使用參照的使用者造成任何問題。
這應該不會在日後使用時造成問題,因為擁有參照在概念上與擁有 VMO 的額外控制代碼類似。
隱私權注意事項
不適用
測試
如果現有測試會查詢參照或切片上的歸因,則必須更新。
說明文件
zx_object_get_info 系統呼叫的文件將會更新。
缺點、替代方案和未知事項
這種設計的缺點之一是,如果使用父項 ID 判斷擁有網頁的 VMO,可能會因巢狀參照而產生重複計算的錯誤。
另一種做法是擴大分享範圍,納入參照和切片,以及寫入時複製的子項。這項變更會對系統造成較大的影響,因為這會改變寫入時複製的複製作業歸因,且所有 VMO 的 USS 和 PSS 計算方式都必須修改。