Android 17 以上版本支援記憶體限制器,這項系統服務會使用 Linux cgroup v2 監控及限制應用程式程序的記憶體用量。記憶體限制器可防止個別應用程式耗用過多系統記憶體,進而減輕系統整體記憶體壓力,並避免系統大量終止重要程序,導致記憶體不足 (OOM)。
機制
記憶體限制器會與活動管理服務 (AMS) 整合,追蹤程序生命週期事件和狀態變化。記憶體限制器會使用 Linux 核心 cgroup v2 檔案系統,強制執行記憶體限制。
如要使用記憶體限制器,裝置核心必須支援 cgroup v2 和 memory 控制器。這項服務特別依賴下列屬性:
memory.high- 軟性限制。如果超出上限,系統就會限制程序,核心也會嘗試從中回收記憶體。
memory.swap.max- 限制程序可用的交換空間量。
對應用程式的影響
如果應用程式未超出記憶體限制,就不會受到記憶體限制器影響。
當應用程式超過 memory.high 限制時,核心會逐出應用程式的檔案支援記憶體,並換出其匿名記憶體,讓應用程式維持在限制內。由於系統會逐出並交換應用程式,應用程式的執行速度可能會變慢。
在極端情況下,如果應用程式持續分配匿名記憶體,且裝置的交換空間不足,應用程式可能無法分配記憶體,因此很可能會當機。
程序監控
記憶體限制器預設會監控應用程式程序 (UID >= 10000)。系統程序通常會排除在外,以利驗證核心系統穩定性。
記憶體限制器會根據程序的狀態指派記憶體限制:
可見的程序是指使用者可察覺的程序,例如前景活動、前景服務或其他可察覺的抖動狀態。
不可見的程序是指使用者看不到或無法互動的背景程序。
下表將特定程序狀態對應至記憶體限制:
| 程序狀態 | 記憶體限制 |
|---|---|
PERSISTENT | 未限制 |
PERSISTENT_UI | 未限制 |
TOP | 顯示 |
BOUND_TOP | 顯示 |
FOREGROUND_SERVICE | 隱藏 |
BOUND_FOREGROUND_SERVICE | 隱藏 |
IMPORTANT_FOREGROUND | 顯示 |
IMPORTANT_BACKGROUND | 隱藏 |
TRANSIENT_BACKGROUND | 隱藏 |
BACKUP | 隱藏 |
SERVICE | 隱藏 |
RECEIVER | 隱藏 |
TOP_SLEEPING | 顯示 |
HEAVY_WEIGHT | 隱藏 |
HOME | 隱藏 |
LAST_ACTIVITY | 隱藏 |
CACHED_ACTIVITY | 快取 |
CACHED_ACTIVITY_CLIENT | 快取 |
CACHED_RECENT | 快取 |
CACHED_EMPTY | 快取 |
在快取狀態下,程序會凍結,然後盡可能回收。
如果程序超出指派的 memory.high 限制,記憶體限制器會偵測到該事件,並觸發偵錯動作,例如擷取記憶體設定檔或將異常情況記錄到 statsd。
設定
使用 vendor 分區中的 XML 檔案設定記憶體限制器。您可以根據裝置的特定記憶體限制,調整絕對記憶體限制。
檔案路徑:
/vendor/etc/memory-limiter-config.xml預設設定:如果找不到設定檔,或設定檔無法讀取或無效,系統就會停用記憶體限制器。
XML 格式
設定檔會遵循 memory-limiter-config.xsd 中定義的結構。您可以在檔案中定義多個限制集,服務會根據裝置的可用 RAM 選擇最合適的限制集。所有記憶體值都以 MiB 為單位定義。
<MemoryLimiterConfig>
<version>1</version>
<configList>
<limitSet>
<!-- Limits for a phone with at least 14G of ram: 8G/4G/4G/4G -->
<minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
<memVisible>8192</memVisible>
<memNotVisible>4096</memNotVisible>
<swapVisible>4096</swapVisible>
<swapNotVisible>4096</swapNotVisible>
</limitSet>
</configList>
</MemoryLimiterConfig>
version- 識別設定版本的正整數。這必須是 1。
minimumRequiredMemTotal- 這個限制生效所需的最低可用系統記憶體。
memVisible- 可見程序可用的記憶體上限 (
memory.high)。 memNotVisible- 允許非顯示程序的記憶體上限 (
memory.high)。 swapVisible- 可見程序允許的交換限制 (
memory.swap.max)。 swapNotVisible- 允許不可見程序使用的交換空間上限 (
memory.swap.max)。
修改設定
如要變更全系統限制,請按照下列步驟操作:
- 修改
/vendor/etc/memory-limiter-config.xml。 - 重新啟動裝置或
system_server,變更才會生效。
殼層指令
您和開發人員可以使用 am memory-limiter 指令,在執行階段與服務互動,進行開發和測試:
am memory-limiter <SUB-COMMAND>狀態
status 子指令會回報記憶體限制器的運作狀態:
adb shell am memory-limiter status輸出內容範例:
Memory limiter
enabled monitoring=true ignored=none
visibleMem=1948MB visibleSwap=974MB
notVisibleMem=974MB notVisibleSwap=487MB
started=36 watched=36 watch-failed=0
events=0 processes=36 process-hwm=36
輸出內容中的主要欄位包括:
monitoring- 指出限制器是否正在監控程序。
visibleMem和notVisibleMem- 指出各個狀態的絕對記憶體限制。
events- 程序超出限制的次數。
processes- 受監控的程序數量。
忽略
ignore 子指令會暫時排除 UID 或所有程序,使其不受限制。這項動作適用於效能測試,或允許特定應用程式超出限制。
adb shell am memory-limiter ignore 10087 // Ignore a specific UIDadb shell am memory-limiter ignore all // Ignore all processes (effectively disables limiting)adb shell am memory-limiter ignore none // Resume normal operation
手動
manual 子指令會以自訂的絕對值 (以 MB 為單位),覆寫特定程序 (依程序 ID 或 PID) 的計算限制:
adb shell am memory-limiter manual 1234 1024 // Set a 1024 MB limit for PID 1234adb shell am memory-limiter manual 1234 none // Remove the manual override for PID 1234
手動覆寫只會套用至程序的生命週期。如果程序重新啟動,系統會根據狀態還原為預設限制。