Android 17 以上版本支援程序記憶體守護程式 (PMGD),可主動管理各程序的記憶體用量,保護系統健康狀態和使用者體驗。這個 Daemon 會對特定目標程序強制執行記憶體上限,並驗證隔離的記憶體流失或高點不會導致系統效能全面下降,進而提升裝置整體穩定性。
傳統的全域低記憶體終止程序只會在整個系統承受壓力時運作,但 PMGD 採取的是精細方法。精靈會監控目標程序的 Control Group v2 記憶體值,藉此達成上述目的。當目標程序超出設定的記憶體限制時,pmgd 會記錄 Statsd 記憶體原子,然後終止程序,藉此處理違規行為。
運作方式
精靈會使用 inotify 監聽記憶體壓力事件 (特別是使用 memory.events 的高記憶體活動)。當受監控的程序觸發記憶體事件時,pmgd 會執行下列動作:
- 匿名記憶體檢查:評估程序的匿名記憶體。如果超過設定的
anon_limit_in_mb,pmgd會立即終止程序。 - 回收等待期:如果匿名記憶體低於指定的匿名記憶體限制,
pmgd會等待系統回收寬限期 (reclaim_wait_time_secs)。 - 回收後的記憶體評估:如果目標程序的
memory.current在寬限期過後仍大於或等於memory.high,或匿名記憶體超過anon_limit_in_mb,pmgd會立即終止程序。
這個程序會持續執行,直到程序遭終止,或程序回收記憶體,使記憶體用量低於指定限制為止。
系統健康狀態功能
- 重新啟動頻率限制:為避免循環啟動或持續當機,
pmgd會追蹤/data/misc/pmgd/history.json中的程序終止情形。在每次重新啟動裝置時,這個精靈會將程序限制為單一pmgd啟動的終止程序。
SELinux 設定
SELinux 政策會限制 PMGD 監控程序的權限。如果您設定 PMGD 監控政策不允許的程序網域 (例如廠商專屬的系統程序),PMGD 就無法監控該程序,且您可能會在 logcat 中看到 SELinux 拒絕訊息。
如要允許 PMGD 監控其他網域中的程序,您必須更新 PMGD 的裝置專屬 SELinux 政策,藉此擴充 PMGD 的權限。
以下是 device/<vendor>/<device>/sepolicy/pmgd.te 檔案範例,可新增對新網域的存取權:
# Allow pmgd to access vendor_system_apps
r_dir_file(pmgd, vendor_system_apps)
如要進一步瞭解如何編寫裝置專屬政策,請參閱「實作 SELinux」。
供應商定義的設定
PMGD 設定是由供應商主導,並透過必要的 JSON 檔案 /vendor/etc/pmgd/config.json 進行設定。這份清單會列出要追蹤的程序、設定的記憶體限制設定檔 (使用 cgroup 工作設定檔),以及以 MB 為單位的匿名記憶體硬性限制。
供應商設定欄位
提供的 JSON 設定是程序及其限制的清單,由下列欄位定義:
| 欄位 | 類型 | 必填 | 說明 | 預設 |
|---|---|---|---|---|
target_cmd |
字串 | 是 | 要監控的目標程序指令名稱,例如 system_server。 |
不適用 |
uid |
整數 | 否 | 程序的使用者 ID (UID)。如果省略,pmgd 會將規則全域套用至任何符合 target_cmd 的程序。 |
不適用 |
reclaim_wait_time_secs |
整數 | 否 | 系統在重新評估記憶體限制前,等待回收記憶體的緩衝時間 (以秒為單位)。 | 5 |
mem_limit_profile |
字串 | 是 | 設定 `memory.high` 的 cgroup 工作設定檔名稱。這項設定用於設定程序記憶體限制。 | 不適用 |
anon_limit_in_mb |
整數 | 是 | 以 MB 為單位的最終匿名記憶體限制。如果匿名記憶體使用率超過這個值,pmgd 會立即終止程序。 |
不適用 |
additional_task_profiles |
字串清單 | 否 | 監控作業開始時,適用於程序的任何其他工作設定檔清單。pmgd |
空白清單 |
以下是 vendor/etc/task_profiles.json 中 cgroup 工作設定檔的設定範例:
{
"Attributes": [
...
{
"Name": "MemHigh",
"Controller": "memory",
"File": "memory.high"
}
],
"Profiles": [
{
"Name": "SystemServerMemoryHighLimit",
"Actions": [
{
"Name": "SetAttribute",
"Params":
{
"Name": "MemHigh",
"Value": "1080M"
}
}
]
}
]
}
以下是
vendor/etc/pmgd/config.json中 PMGD 設定的範例:
{
"targets": [
{
"target_cmd": "system_server",
"uid": 1000,
"reclaim_wait_time_secs": 5,
"mem_limit_profile": "SystemServerMemoryHighLimit",
"anon_limit_in_mb": 300
}
]
}