Android 17 以上版本包含記憶體限制器,這項系統服務會使用 Linux cgroup v2 監控及限制應用程式程序的記憶體用量。記憶體限制器可防止個別應用程式消耗過多系統記憶體,進而降低整體記憶體壓力,並防止系統在記憶體不足時,過度終止重要的前景和快取程序。
機制
記憶體限制器與活動管理工具服務 (AMS) 整合,可追蹤程序生命週期事件和狀態變更。記憶體限制器會使用 Linux 核心 cgroup v2 階層強制執行記憶體限制。
如要支援記憶體限制器,裝置核心必須啟用 cgroup v2 和 memory 控制器。這項服務特別仰賴下列屬性:
memory.high- 軟性限制。超過上限時,系統會限制程序,核心也會嘗試主動回收該程序的頁面。
memory.swap.max- 限制程序可使用的交換空間 (例如 ZRAM) 上限。
對應用程式的影響
如果應用程式在記憶體限制內運作,就不會受到記憶體限制器的影響。
當應用程式超過 memory.high 限制時,核心會清除應用程式的乾淨檔案支援記憶體,並交換其閒置匿名記憶體,讓應用程式保持在限制範圍內。由於這項頁面移除和交換活動,應用程式可能會暫時受到執行限制,但仍會繼續執行。
在極端情況下 (例如記憶體流失失控,應用程式在交換空間用盡後繼續分配匿名記憶體),應用程式無法分配記憶體,並會終止。
程序監控
根據預設,記憶體限制器會監控應用程式程序 (UID >= 10000)。核心系統程序則不受影響,以維持必要的系統穩定性。
記憶體限制器會根據程序的顯示狀態指派記憶體限制:
可見程序:代管使用者可見 UI 的程序 (例如目前聚焦的活動或進行中的互動)。由於顯示 UI 需要較大的工作集來處理算繪和圖形管道,因此可見程序會獲得更寬鬆的記憶體限制。
不可見程序:在背景執行工作,但未顯示 UI 的程序 (例如背景服務或廣播接收器)。由於這類服務不會算繪 UI 元件,因此受到的限制較嚴格。
下表將特定程序狀態對應至記憶體限制分類:
| 程序狀態 | 記憶體限制 |
|---|---|
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。
設定
在 Android 17 以上版本中,記憶體限制器是使用系統分區 /system/etc/memory-limiter-config.xml 的標準平台設定檔進行設定。
XML 格式
設定檔會遵循 memory-limiter-config.xsd 中定義的結構定義。檔案會定義多個限制組合,並依可用記憶體排序;服務會根據裝置的可用 RAM,選取最高的相符限制組合。所有記憶體值均以 MiB 為單位。
<MemoryLimiterConfig>
<version>1</version>
<configList>
<!-- RAM boundaries account for MemTotal excluding carve-outs. -->
<limitSet>
<!-- Limits for 16GB RAM device [14336, 18432): 10G/5G/5G/5G -->
<minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
<maximumAllowedMemTotal>18432</maximumAllowedMemTotal>
<memVisible>10240</memVisible>
<memNotVisible>5120</memNotVisible>
<swapVisible>5120</swapVisible>
<swapNotVisible>5120</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 12GB RAM device [9216, 14336): 8G/4G/4G/4G -->
<minimumRequiredMemTotal>9216</minimumRequiredMemTotal>
<maximumAllowedMemTotal>14336</maximumAllowedMemTotal>
<memVisible>8192</memVisible>
<memNotVisible>4096</memNotVisible>
<swapVisible>4096</swapVisible>
<swapNotVisible>4096</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 8GB RAM device [6800, 9216): 5G/3G/3G/3G -->
<minimumRequiredMemTotal>6800</minimumRequiredMemTotal>
<maximumAllowedMemTotal>9216</maximumAllowedMemTotal>
<memVisible>5120</memVisible>
<memNotVisible>3072</memNotVisible>
<swapVisible>3072</swapVisible>
<swapNotVisible>3072</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 6GB RAM device [4800, 6800): 4G/2G/2G/2G -->
<minimumRequiredMemTotal>4800</minimumRequiredMemTotal>
<maximumAllowedMemTotal>6800</maximumAllowedMemTotal>
<memVisible>4096</memVisible>
<memNotVisible>2048</memNotVisible>
<swapVisible>2048</swapVisible>
<swapNotVisible>2048</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 4GB RAM device [3200, 4800): 2G/1G/1G/1G -->
<minimumRequiredMemTotal>3200</minimumRequiredMemTotal>
<maximumAllowedMemTotal>4800</maximumAllowedMemTotal>
<memVisible>2048</memVisible>
<memNotVisible>1024</memNotVisible>
<swapVisible>1024</swapVisible>
<swapNotVisible>1024</swapNotVisible>
</limitSet>
</configList>
</MemoryLimiterConfig>
version- 用於識別設定版本的正整數。這必須是
1。 minimumRequiredMemTotal套用這組限制所需的最低系統
MemTotal(以 MiB 為單位,包含下限)。服務會根據核心在/proc/meminfo中回報的可用記憶體總量,評估這個值。瞭解記憶體保留區和邊界:核心
MemTotal值反映的是扣除硬體和韌體記憶體保留區後,作業系統可存取的實體 DRAM。Carve-out 會為 GPU、基頻數據機、相機 ISP、安全執行環境和管理程序等專用硬體元件保留 RAM,通常會耗用 500 MiB 到超過 2 GiB 的實體記憶體。由於
MemTotal低於裝置標榜的實體 DRAM,minimumRequiredMemTotal門檻會包含這些預留空間。舉例來說,指定 16 GB 裝置的設定會指定14336(14 GiB) 的下限,而非16384(16 GiB),而 12 GB 裝置的層級則會指定9216(9 GiB) 的下限。這可確保每部裝置都符合預期級別,無論主機板層級的劃分變化為何。maximumAllowedMemTotal套用這組限制時,系統
MemTotal的上限 (以 MiB 為單位,不含上限值)。如果MemTotal大於或等於這個上限,則不適用設定的限制。如果裝置的記憶體容量為 18,432 MiB 以上或低於 3,200 MiB,記憶體限制器不會套用限制,程序不會受到限制。memVisible套用至可見程序的軟性記憶體限制 (
memory.high),以 MiB 為單位。memNotVisible套用至不可見程序的軟性記憶體限制 (
memory.high),以 MiB 為單位。swapVisible套用至可見程序的置換空間限制 (
memory.swap.max),以 MiB 為單位。swapNotVisible套用至不可見程序的置換空間限制 (
memory.swap.max),以 MiB 為單位。
標準平台限制
在 Android 17 以上版本中,平台會使用 [floor, ceiling) 範圍間隔,在 /system/etc/memory-limiter-config.xml 中指定常見實體 RAM 級別的標準記憶體和交換限制:
| 目標實體 RAM |
MemTotal 範圍 [下限, 上限) (minimumRequiredMemTotal, maximumAllowedMemTotal) |
可見記憶體限制 (memVisible) |
不可見記憶體限制 (memNotVisible) |
可見交換限制 (swapVisible) |
未顯示交換限制 (swapNotVisible) |
|---|---|---|---|---|---|
| 16 GB | [14336, 18432) MiB |
10,240 MiB (10 GiB) | 5,120 MiB (5 GiB) | 5,120 MiB (5 GiB) | 5,120 MiB (5 GiB) |
| 12 GB | [9216, 14336) MiB |
8,192 MiB (8 GiB) | 4,096 MiB (4 GiB) | 4,096 MiB (4 GiB) | 4,096 MiB (4 GiB) |
| 8 GB | [6800, 9216) MiB |
5,120 MiB (5 GiB) | 3,072 MiB (3 GiB) | 3,072 MiB (3 GiB) | 3,072 MiB (3 GiB) |
| 6 GB | [4800, 6800) MiB |
4,096 MiB (4 GiB) | 2,048 MiB (2 GiB) | 2,048 MiB (2 GiB) | 2,048 MiB (2 GiB) |
| 4 GB | [3200, 4800) MiB |
2,048 MiB (2 GiB) | 1,024 MiB (1 GiB) | 1,024 MiB (1 GiB) | 1,024 MiB (1 GiB) |
記憶體限制原則
記憶體限制器設定是根據下列平台原則設計:
生態系統一致性和應用程式相容性:各裝置的記憶體限制一致,可確保整個 Android 生態系統的應用程式效能可預測。應用程式是根據標準記憶體預期開發及測試,維持一致的平台限制可避免非預期的節流或提早終止。
按比例分配資源:平台限制會根據實體 RAM 容量調整:
- 可見程序:分配約 1/2 至 2/3 的實體 RAM 總量,支援活躍的 UI、組合和算繪工作負載。
- 不可見程序:為背景工作分配約 1/4 到 1/3 的實體 RAM 總量。
全面適用:限制會統一套用至裝置上的所有應用程式程序 (UID >= 10000),包括預先安裝的系統和原始設備製造商 (OEM) 應用程式。記憶體限制器不支援許可清單,無法豁免特定應用程式,確保所有應用程式都能公平管理記憶體。如要為重要的互動式 Daemon 設定自我調整
memory.min保護下限,並為個別系統應用程式和服務設定更嚴格、依工作負載校準的memory.high上限,請參閱「系統記憶體預算」。缺少執行階段查詢 API:在 Android 17 以上版本中,應用程式無法在執行階段,透過程式輔助方式查詢指派的記憶體限制。標準平台限制的定義範圍較廣,因此運作良好的應用程式在正常使用期間不會受到限制。
核心回收和交換動態:當應用程式程序接近
memory.high限制時,Linux 核心會專門針對該程序 cgroup 進行記憶體回收。包括捨棄閒置的檔案備份頁面,以及將冷匿名頁面交換至 ZRAM,在不造成全域記憶體壓力的情況下,維持系統流暢度。
殼層指令
開發人員和系統整合商可使用 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- 目前針對各個可見度狀態強制執行的絕對記憶體限制 (
memory.high) 計算值。 visibleSwap和notVisibleSwap- 目前針對各曝光度狀態強制執行的絕對交換限制 (
memory.swap.max) 計算結果。 events- 程序超過指派限制的次數。
processes- 目前受監控的程序數量。
ignore
ignore 子指令會暫時將特定 UID 或所有程序排除在記憶體限制之外。這項功能適用於效能基準測試、壓力測試或診斷記憶體行為:
# Ignore a specific UID adb shell am memory-limiter ignore 10087# Ignore all processes (temporarily disables limiting) adb shell am memory-limiter ignore all# Resume normal limiting operation adb shell am memory-limiter ignore none
手動
manual 子指令會以自訂絕對值 (以位元組為單位),覆寫特定程序 (依程序 ID (PID)) 的計算限制。這個值必須是整數,但可以加上 MB 後置字元表示 MiB,或加上 GB 後置字元表示 GiB:
# Set a 1GiB limit for PID 1234 adb shell am memory-limiter manual 1234 1073741824# Set a 1GiB limit for PID 1234 adb shell am memory-limiter manual 1234 1024MB# Set a 1GiB limit for PID 1234 adb shell am memory-limiter manual 1234 1GB# Remove the manual override for PID 1234 adb shell am memory-limiter manual 1234 none
手動覆寫僅適用於該特定程序執行個體的生命週期。如果程序重新啟動,則會根據其狀態返回標準限制。
手動覆寫值不得超過實體系統限制。