RFC-0012:Zircon 可捨棄記憶體

RFC-0012:Zircon 可捨棄記憶體
狀態已接受
區域
  • 核心
說明

說明使用者空間應用程式向核心指出特定記憶體緩衝區可供回收的機制。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2020-10-27
審查日期 (年-月-日)2020-12-02

摘要

這份 RFC 說明瞭使用者空間應用程式向核心指出特定記憶體緩衝區可供回收的機制。當系統的可用記憶體不足時,核心就能隨意捨棄這些緩衝區。

提振精神

在 Zircon 等超額承諾系統中,管理空閒記憶體是個複雜的問題,因為使用者應用程式可配置的記憶體,可能會超過系統目前可用的記憶體。這項功能是透過使用虛擬記憶體物件 (VMO) 來達成,這些物件會在其中的部分內容提交時,由實體頁面延遲備份。

如果您高估了任何時間點會使用的實體記憶體量,並根據此情況要求進一步分配記憶體,可能會讓系統保留空閒記憶體。這可能會影響效能,因為應用程式會大量使用這類記憶體來快取資料。另一方面,如果低估目前使用的空閒記憶體量,可能會導致系統快速用盡所有可用記憶體,進而導致記憶體不足 (OOM) 的情況。此外,「free」記憶體的定義本身也相當複雜。

Zircon 核心會監控可用實體記憶體的數量,並在不同層級產生記憶體壓力信號。這些信號的目的,是讓使用者空間應用程式根據系統層級的空閒記憶體等級,縮減 (或增加) 記憶體占用空間。雖然這有助於避免系統記憶體不足,但將這些信號的發起端 (核心) 與回應端 (使用者應用程式) 解耦並非理想做法。回應記憶體壓力的程序沒有足夠的背景資訊,無法判斷應釋放多少記憶體;核心可以更清楚地掌握系統的全球記憶體用量,也可以考量其他形式的可回收記憶體,例如可淘汰的使用者分頁機記憶體。

這份 RFC 提出了一種機制,可讓核心在記憶體壓力下直接回收使用者空間記憶體緩衝區。這種做法有幾個優點:

  • 這可讓您更有效地控制要淘汰多少記憶體;核心可以查看可用記憶體層級,並只淘汰所需的記憶體。
  • 核心可以使用 LRU 配置來捨棄記憶體,這可能更適合在記憶體中容納目前的工作集。
  • 使用者空間有時會在回應記憶體壓力信號時,緩慢地釋放記憶體。在某些情況下,系統可能來不及復原。
  • 喚醒用戶端以回應記憶體壓力時,有時可能需要更多記憶體。

設計

總覽

可捨棄記憶體通訊協定大致會以以下方式運作:

  1. 使用者空間程序會建立 VMO,並將其標示為「可捨棄」
  2. 在直接存取 VMO (zx_vmo_read/zx_vmo_write) 或透過其位址空間中的對應項目 (zx_vmar_map) 存取 VMO 之前,程序會鎖定 VMO,表示 VMO 正在使用中。
  3. 完成後,系統會解鎖 VMO,表示不再需要該 VMO。核心會將所有已解鎖的棄置 VMOs 視為可回收的對象,並在記憶體壓力下自由棄置。
  4. 當程序需要再次存取 VMO 時,就會嘗試鎖定 VMO。這個鎖現在可以透過下列兩種方式成功運作。
    • 鎖定作業可以成功,且 VMO 的頁面仍完好無缺,也就是核心尚未捨棄該頁面。
    • 如果核心已捨棄 VMO,鎖定作業就會成功,同時也會向用戶端指出其頁面已遭到捨棄,以便他們重新初始化或採取其他必要的動作。
  5. 完成後,系統會再次解鎖 VMO。你可以視需要重複執行這項操作。

請注意,可捨棄的記憶體並非用來直接取代記憶體壓力信號。監控記憶體壓力變化仍可用於其他元件層級的決策,例如選擇何時要啟動記憶體密集的活動或執行緒。日後,我們也可以使用這些信號,在元件中終止閒置的程序。記憶體壓力信號也能讓元件更精確地控管要釋放哪些記憶體,以及何時釋放。

Discardable Memory API

我們可以擴充現有的 zx_vmo_create()zx_vmo_op_range() 系統呼叫,以支援這項功能。

  • zx_vmo_create() 將擴充支援新的 options 標記 - ZX_VMO_DISCARDABLE。這個標記可與 ZX_VMO_RESIZABLE 搭配使用。不過,關於可調整大小的 VMOs 的一般建議也適用於可捨棄的 VMOs,在處理程序之間共用可調整大小的 VMOs 可能會造成危險,因此應避免這麼做。

  • zx_vmo_op_range() 將擴充支援新的作業,提供鎖定和解鎖功能 - ZX_VMO_OP_LOCKZX_VMO_OP_TRY_LOCKZX_VMO_OP_UNLOCK

  • 鎖定和解鎖會套用至整個 VMO,因此 offsetsize 應涵蓋 VMO 的整個範圍。在 VMO 中鎖定和解鎖較小的範圍會發生錯誤。雖然目前的實作方式並未嚴格要求 offsetsize,但只要確保系統只將 VMO 的整個範圍視為有效,就能夠在日後新增子範圍支援功能,而無須變更用戶端的行為。

  • ZX_VMO_OP_TRY_LOCK 作業會嘗試鎖定 VMO,但可能會失敗。如果核心未捨棄 VMO,則會成功;如果核心已捨棄 VMO,則會失敗並傳回 ZX_ERR_NOT_AVAILABLE。如果失敗,用戶端應會嘗試使用 ZX_VMO_OP_LOCK 再次執行,只要傳入的引數有效,就保證會成功。ZX_VMO_OP_TRY_LOCK 運算是輕量級選項,可嘗試鎖定 VMO 而無須設定緩衝區引數。用戶端也可以選擇在無法鎖定 VMO 後不採取任何行動。

  • ZX_VMO_OP_LOCK 作業也需要 buffer 引數,這是指向 zx_vmo_lock_state 結構體的輸出指標。這個結構體可讓核心傳回客戶可能覺得實用的資訊,其中包含:

    • offsetsize 追蹤鎖定的範圍:這是用戶端傳入的 sizeoffset 引數。這些值純粹是為了方便起見而傳回,這樣客戶就不必另外追蹤範圍,而是可以直接使用傳回的結構體。如果呼叫成功,這些值一律會與傳遞至 zx_vmo_op_range() 呼叫的 sizeoffset 值相同。
    • discarded_offsetdiscarded_size 追蹤已捨棄的範圍:這是包含已捨棄網頁的鎖定範圍內的最大範圍。這個範圍內的頁面不一定都已遭到捨棄,它只是這個範圍內所有已捨棄的子範圍的聯集,也可能包含未遭到捨棄的頁面。在目前的 API 中,如果核心已捨棄,則捨棄的範圍會跨越整個 VMO。如果未捨棄,discarded_offsetdiscarded_size 都會設為零。
  • 鎖定本身不會在 VMO 中提交任何頁面。它只是將 VMO 的狀態標示為「不可捨棄」的核心。用戶端可以使用任何適用於一般 VMOs 的現有方法,例如 zx_vmo_write()ZX_VMO_OP_COMMIT,對應 VMO 並直接寫入對應的位址,在 VMO 中提交頁面。

// |options| supports a new flag - ZX_VMO_DISCARDABLE.
zx_status_t zx_vmo_create(uint64_t size, uint32_t options, zx_handle_t* out);

// |op| is ZX_VMO_OP_LOCK, ZX_VMO_OP_TRY_LOCK, and ZX_VMO_OP_UNLOCK to
// respectively lock, try lock and unlock a discardable VMO.
// |offset| must be 0 and |size| must the size of the VMO.
//
// ZX_VMO_OP_LOCK requires |buffer| to point to a |zx_vmo_lock_state| struct,
// and |buffer_size| to be the size of the struct.
//
// Returns ZX_ERR_NOT_SUPPORTED if the vmo has not been created with the
// ZX_VMO_DISCARDABLE flag.
zx_status_t zx_vmo_op_range(zx_handle_t handle,
                            uint32_t op,
                            uint64_t offset,
                            uint64_t size,
                            void* buffer,
                            size_t buffer_size);

// |buffer| for ZX_VMO_OP_LOCK is a pointer to struct |zx_vmo_lock_state|.
typedef struct zx_vmo_lock_state {
  // The |offset| that was passed in.
  uint64_t offset;
  // The |size| that was passed in.
  uint64_t size;
  // Start of the discarded range. Will be 0 if undiscarded.
  uint64_t discarded_offset;
  // The size of discarded range. Will be 0 if undiscarded.
  uint64_t discarded_size;
} zx_vmo_lock_state_t;

zx::vmo 介面將擴充,以便使用 op_range() 支援 ZX_VMO_OP_LOCKZX_VMO_OP_TRY_LOCKZX_VMO_OP_UNLOCK 運算。Rust、Go 和 Dart 繫結也會隨之更新。

這個 API 可讓用戶端靈活地在多個程序中共用可捨棄的 VMO。每個需要存取 VMO 的程序都可以獨立執行,並視需要鎖定和解鎖 VMO。不需要根據鎖定狀態的假設,在程序之間進行仔細的協調。只有在沒有人鎖定 VMO 時,核心才會將其視為可回收的項目。

VMOs 的限制

  • 可捨棄記憶體 API 僅支援 VmObjectPaged 類型,因為 VmObjectPhysical 無法依定義捨棄。

  • 由於在複本階層中捨棄 VMOs 可能會導致意外行為,因此 API 與 VMO 複本 (快照和 COW 複本) 和切片不相容。zx_vmo_create_child() 系統呼叫會在可捨棄的 VMOs 上失敗。

  • ZX_VMO_DISCARDABLE 旗標無法用於 zx_pager_create_vmo()options 引數。這主要是因為可透過 pager 備份的 VMOs 可進行複製,而可捨棄的 VMOs 則無法。此外,對於使用分頁器支援的 VMOs,系統會隱含可捨棄性,因此不需要額外標記。

與現有 VMO 作業互動

現有 VMO 作業的語意會維持不變。舉例來說,zx_vmo_read() 在允許作業前,不會先驗證可捨棄的 VMO 是否已上鎖。客戶有責任確保在存取 VMO 時鎖定 VMO,以確保核心不會從底層捨棄 VMO。這可限制這項變更的表面積。核心提供的唯一保證是,在 VMO 鎖定時,核心不會捨棄 VMO 的頁面。

只要用戶端在存取對應項目前鎖定 VMO,任何 VMO 對應項目都會繼續有效,即使 VMO 已遭到捨棄也不例外。如果已捨棄 VMO,用戶端就不需要重新建立對應項目。

核心捨棄 VMO 後,如果未先鎖定 VMO 就執行任何後續作業,作業會失敗,因為 VMO 沒有已提交的頁面,也沒有可用於按需提交頁面的機制。舉例來說,zx_vmo_read() 會因 ZX_ERR_OUT_OF_RANGE 而失敗。如果 VMO 是在程序位址空間中對應,對應位址的未鎖定存取作業會導致致命的頁面錯誤例外狀況。

核心實作

追蹤中繼資料

  • VmObjectPaged 中的 options_ 位元遮罩將擴充為支援 kDiscardable 標記;我們目前只使用 32 位元中的 4 位元。
  • 系統會在 VmObjectPaged 中新增 lock_count 欄位,用於追蹤 VMO 上未完成的鎖定作業數量。
  • 核心會維護一份可回收的 VMOs 全域清單,也就是系統上所有已解鎖的可捨棄 VMOs。清單會更新為以下內容:
    • ZX_VMO_OP_LOCK 會增加 VMO 的 lock_count。如果 lock_count 從 0 變為 1,系統就會將 VMO 從全域可回收清單中移除。
    • ZX_VMO_OP_UNLOCK 會遞減 VMO 的 lock_count。如果 lock_count 降至 0,系統會將 VMO 新增至全域可回收清單。

聲明版權歸屬邏輯

lock_count 降至零時,可捨棄的 VMOs 會加入全球可回收清單,並在再次上鎖時移除。這會維護系統上所有已解鎖可捨棄的 VMOs 的 LRU 順序。在記憶體壓力下,核心可以依序從此清單中將 VMOs 從佇列中移除並捨棄,並在每次移除後檢查可用記憶體等級。這是實際上回收邏輯可能的簡化版本。後續會提到其他需要考量的事項。

捨棄作業

在核心端實作「捨棄」功能,方法是取消提交 VMO 的所有頁面,並將 VMO 的內部狀態設為 discarded。如果 VMO 狀態為 discardedVmObjectPaged::GetPageLocked() 會以 ZX_ERR_NOT_FOUND 失敗。後續的 ZX_VMO_OP_LOCK 作業會清除 discarded 狀態。GetPageLocked() 是所有對 VMO 網頁存取的入口,包括透過 zx_vmo_read/write 系統呼叫和透過 VM 對應的網頁存取。這可讓我們在已捨棄的解鎖 VMO 上失敗的系統呼叫,並在透過對應項目存取已捨棄的解鎖 VMO 時產生例外狀況。

實作

這是新的 API,因此目前沒有任何依附元件。核心端實作作業可以獨立完成。實作 API 後,使用者空間用戶端就可以開始採用。

成效

效能影響會因用戶端用途而異。使用 API 時,用戶端應留意幾件事。

  • zx_vmo_op_range() 系統呼叫可在存取前鎖定及解鎖可丟棄的 VMOs,這可能會在效能關鍵路徑上增加明顯的延遲時間。因此,系統呼叫應用於可容許或隱藏延遲時間增加的程式碼路徑。
  • 由於快取會在記憶體中保留較長的時間,因此用戶端效能也可能會提升。在記憶體壓力下,客戶端必須捨棄的緩衝區,現在可以保留更久的時間,因為核心只會捨棄所需的記憶體。用戶端可以透過快取命中率、需要重新初始化的緩衝區次數等,追蹤這項變更。

安全性考量

無。

隱私權注意事項

無。

測試

  • 核心測試 / 單元測試,可從多個執行緒測試新的 API。
  • 單元測試,用於驗證核心端的回收行為,也就是只能捨棄已解鎖的 VMOs。

說明文件

我們需要更新 Zircon 系統呼叫說明文件,加入新的 API。

缺點、替代方案和未知事項

鎖定 VMO 內的範圍

回收作業的精細程度會設為整個 VMO,而不會支援 VMO 內的細微刪除作業。這有幾個原因。

  • 重建已捨棄部分網頁的 VMO 可能會很棘手。考量一般用途,也就是使用 VMO 代表匿名記憶體緩衝區,重新填入已捨棄的頁面可能會是零填充,這可能不一定適合未捨棄的頁面。只保留 VMO 的子集也可能沒有價值,也就是說,只有在 VMO 填入完整資料時才有意義。
  • VMO 精細度可讓 VmObjectPaged 導入作業簡單化,只需追蹤少量中繼資料。我們不需要追蹤鎖定的範圍,以便日後與解鎖的範圍比對。也不需要進行複雜的範圍合併作業。
  • 它還可讓回收邏輯保持輕量化,讓您一次釋出大量記憶體。若要支援頁面精細度,可能需要維護頁面佇列和過時的棄用頁面,類似我們用來剔除使用者分頁器支援頁面的機制。

建議的 API 會保留這個選項,以便在未來視需要指示可回收的範圍,而 zx_vmo_op_range() 中的 offsetsize 引數目前未使用。在鎖定 API (網頁精細鎖定) 中加入範圍支援功能,似乎是目前提案的自然延伸。對於使用個別 VMOs 備份小型可捨棄區域的客戶而言,這項功能將帶來實質效益。

核心實作捨棄

當核心重新使用可捨棄的 VMO 時,會解除其頁面,並追蹤其狀態為 discarded。日後針對網頁提出的解鎖要求會在 discarded 狀態下失敗;一旦 VMO 再次鎖定,discarded 狀態就會清除。另一種做法是直接取消提交頁面,而不需要明確追蹤狀態。不過,追蹤 discarded 狀態可讓您採用更嚴格的失敗模型。舉例來說,假設用戶端在其位址空間中對應了可捨棄的 VMO,而核心會在某個時間點捨棄該 VMO。如果用戶端現在嘗試透過對應方式存取 VMO,但未先鎖定 VMO,就會發生致命的頁面錯誤。但如果核心只會解除頁面承諾,後續的未鎖定存取作業只會導致零頁面悄悄交給用戶端。這可能會導致系統無法偵測到問題,或是因意外的零頁而導致更細微的錯誤。

另一種做法是將 VMO 的內部大小調整為零。這可讓我們預設取得所需的失敗模型,而無需進行任何明確的狀態追蹤。不過,除了使用者看到的外部大小之外,您還必須追蹤 VMO 的內部實作定義大小。雖然內部實作定義的大小是個實用技巧,日後也可能對其他用途有所助益,但兩種大小概念分開會造成混淆,且容易發生錯誤。因此,在我們找到其他具體的用途,並能明確指出除了外部尺寸外,內部尺寸也能帶來益處之前,我們會選擇避免採用這種做法。

使用原子功能加快鎖定 API 的速度

這項鎖定最佳化功能提供另一種低延遲的選項,可用來鎖定及解鎖可丟棄的 VMOs,並可供預期鎖定及解鎖頻率相當高的用戶端使用。這純粹是效能最佳化,因此我們日後可能會視需要新增這項功能。

這個 API 會使用名為 Metex 的鎖定基本元素,與 Zircon futex 類似,可透過使用者空間原子化快速鎖定,進而節省系統呼叫的成本。

可捨棄的 VMO 可與 metex 建立關聯,用於鎖定和解鎖該 VMO,而非 zx_vmo_op_range() 系統呼叫。metex 可有三種狀態:已鎖定 (使用者空間用戶端正在使用)、可捨棄 (可供核心回收) 和「需要系統呼叫」(可能已由核心回收,需要系統呼叫才能檢查狀態)。您可以透過在鎖定和可丟棄之間的 metex 狀態中,以原子方式翻轉狀態,在不進入核心的情況下鎖定和解鎖 VMO。當核心捨棄 VMO 時,會將其狀態以原子方式翻轉為「需要系統呼叫」,表示用戶端需要與核心同步,以便檢查已捨棄的狀態。這項提案的詳細內容超出本 RFC 的範圍,將在另一份 RFC 中提供。

以 Pager 為基礎的建立 API

任何由分頁器支援的 VMO 本質上都是可捨棄的 VMO,因為分頁器提供機制,可視需要重新填入已捨棄的頁面。本 RFC 中提出的棄置記憶體類型為匿名棄置記憶體;另一類型則是檔案支援的棄置記憶體,例如由 blobfs 使用者分頁機填入的 blob 記憶體內表示法。考量這一點,我們可以考慮使用其他建立 API,讓可捨棄的 VMOs 與分頁器建立關聯。VMO 建立呼叫可能如下所示:

zx_pager_create(0, &pager_handle);

zx_pager_create_vmo(pager_handle, 0, pager_port_handle, vmo_key, vmo_size,
                    &vmo_handle);

鎖定和解鎖功能會如同先前所述,使用 zx_vmo_op_range() 運作。只有在解鎖時,核心才能自由捨棄 VMO 中的頁面。

這項做法的優點是,它可為我們提供適用於所有類型可捨棄記憶體的統一建立 API,無論該記憶體是否為檔案支援或匿名。

不過,在這種情況下,分頁器並未真正用於特殊用途。由於它處理的是一般匿名記憶體,因此可能只會在需要時提供零頁面。當您需要以特定方式填入特定內容的網頁時,使用分頁器會更適合。為了在需要時建立零頁,而引入額外的間接層 (無論是技術複雜性還是效能負載) 似乎是不必要的;這個功能已存在於一般 (非 pager 支援) VMOs 的核心中。

使用保留物件進行鎖定

這裡提出的鎖定 API 可能會導致錯誤,導致可捨棄的 VMO 遭到意外 (或惡意) 解鎖。在某些情況下,程序會認為 VMO 已鎖定,但另一個程序已將其解鎖,也就是說,第二個程序會發出額外的解鎖指令。這會導致第一個程序在存取 VMO 時發生錯誤或異常終止,即使該程序在存取前已正確鎖定 VMO 也一樣。

我們可以使用保留者物件實作鎖定功能,而非鎖定和解鎖作業,這樣做可在建立 VMO 時鎖定,並在銷毀時解鎖。

zx_vmo_create_retainer(vmo_handle, &retainer_handle);

只要固定手柄處於開啟狀態,VMO 就會保持鎖定狀態。在上例中,兩個程序都會使用各自的保留者來鎖定 VMO,因此不會發生錯誤的額外解鎖情形。這種鎖定模型可降低這類錯誤的發生機率,並在發生時輕鬆進行診斷。

缺點是核心需要儲存更多中繼資料,才能追蹤 VMO 的鎖定狀態。我們現在有與可捨棄的 VMO 相關聯的保留物件清單,而非單一 lock_count 欄位。如要避免惡意使用者導致核心無限成長,我們也可能會限制這份清單的長度。

索回順序的優先順序

為簡化起始流程,核心會依 LRU 順序回收已解鎖的棄置 VMOs。我們可以探索讓用戶端在日後明確指定回收優先順序 (各優先順序頻帶中的 VMOs 仍可依 LRU 順序回收)。建議的 API 會透過 ZX_VMO_OP_UNLOCKzx_vmo_op_range() 中目前未使用的 buffer 參數,讓您在日後支援此功能。

不過,我們可能不需要這麼嚴格的控制機制;全域 LRU 順序可能就足夠了。如果用戶端想要進一步掌控何時回收特定緩衝區,可以改為選擇記憶體壓力信號,並自行放棄這些緩衝區。

與其他回收策略的互動

目前還有兩種其他機制可用來回收記憶體:

  • 使用者分頁器支援記憶體 (記憶體內 blob) 的頁面淘汰作業,會在記憶體壓力達到 CRITICAL 等級 (且接近 OOM) 時由核心執行。
  • 記憶體壓力信號,當使用者空間元件在記憶體壓力等級為「CRITICAL」和「WARNING」時,會釋出記憶體。

我們需要找出這個配置中可捨棄的記憶體所在位置,確保沒有單一回收策略會承擔大部分負擔。舉例來說,我們可能會想維持某種檔案支援記憶體與可捨棄記憶體的淘汰比率。

鎖定使用 pager 支援的 VMOs

我們日後可以將 ZX_VMO_OP_LOCKZX_VMO_OP_UNLOCK 作業擴展至 pager 支援的 VMOs。我們一直希望支援鎖定使用者 pager 支援的 VMOs,如果有具體用途,我們可能會提供這項功能。舉例來說,blobfs 可以為 blobfs 認為重要的 blob 或不太符合核心 LRU 淘汰方案的 blob 鎖定記憶體中的 VMOs,藉此避免重新分頁的效能成本。

鎖定使用者分頁器支援的 VMOs 會與可捨棄的記憶體 API 完美搭配,因為使用者分頁器支援的 VMOs 基本上可視為一種可捨棄的記憶體,其中使用者分頁器會提供專門機制來重新填充頁面。鎖定和解鎖功能會套用至這兩種可丟棄式記憶體,這兩種記憶體之間的主要差異在於建立和填入的方式。

決定何時重新填入已棄用的 VMOs

用戶端可能需要一種方法,以便判斷何時可以安全地重新填入已棄用的 VMO。如果在記憶體壓力下重新填充 VMO,則提交的額外頁面可能會使系統的記憶體壓力惡化,導致系統更接近 OOM。此外,一旦 VMO 解鎖,如果記憶體壓力持續存在,系統就可能會捨棄 VMO。這可能會導致資源耗盡,也就是說,用戶端會不斷重新填入 VMO,但很快就會看到核心將其捨棄。

目前觀察系統記憶體壓力等級的唯一機制,就是訂閱 fuchsia.memorypressure 服務,但這對此用途來說可能會相當昂貴。我們可以考慮擴充這項服務,提供執行一次性查詢的方法。我們也可以考慮透過 zx_vmo_lock_state 結構體傳回壓力等級的指標,可能是目前的記憶體壓力等級本身,或是粗略擷取系統是否處於記憶體壓力狀態的布林值。

用於追蹤未鎖定的 VMO 存取權的偵錯輔助工具

在未鎖定的可丟棄 VMOs 上啟用失敗的系統呼叫時,啟用建構標記後方的額外檢查功能可能會很有幫助。這可協助開發人員輕鬆找出 VMO 存取作業未先鎖定的問題,而不需要依賴 VMO 在記憶體壓力下遭到捨棄,且只有在發生失敗時才會發生。隨著我們日後新增範圍支援功能,對 VMO 的鎖定狀態進行這類檢查的成本可能會迅速增加,因此無法在實際工作環境中啟用,但可能會證明做為偵錯工具相當實用。

透過對應捕捉未鎖定的 VMO 存取權可能較難實作。我們可以透過以下幾種方法來達成這項目標:

  • 在解鎖已對應的棄用 VMO 時取消對應。採用這種做法時,我們需要確保現有的 VMO / VMAR 語意保持不變。
  • 在鎖定 / 解鎖呼叫周圍教導包裝函式,告訴 ASAN,解鎖的 VMO 對應項目應視為遭到破壞,直到再次鎖定為止,使用 ASAN_POISON_MEMORY_REGION 介面。

既有技術與參考資料