Android 17 e versioni successive supportano Memory Limiter, un servizio di sistema che monitora e limita la memoria utilizzata dei processi delle applicazioni utilizzando Linux cgroup v2. Memory Limiter impedisce alle singole app di consumare una quantità eccessiva di memoria di sistema, il che riduce la pressione della memoria a livello di sistema e impedisce l'eliminazione aggressiva dei processi critici per esaurimento della memoria (OOM).
Meccanismo
Memory Limiter si integra con Activity Manager Service (AMS) per monitorare gli eventi del ciclo di vita dei processi e le modifiche dello stato. Memory Limiter applica i limiti di memoria utilizzando il file system cgroup v2 del kernel Linux.
Per utilizzare Memory Limiter, il kernel del dispositivo deve supportare cgroup v2 e il controller memory. Il servizio si basa in particolare sui seguenti attributi:
memory.high- Un limite flessibile. Quando viene superato, il processo viene limitato e il kernel tenta di recuperare la memoria.
memory.swap.max- Limita la quantità di spazio di swap che il processo può utilizzare.
Impatto sulle app
Le app che non superano i limiti di memoria non sono interessate da Memory Limiter.
Quando un'app supera il limite memory.high, il kernel espelle la memoria supportata da file dell'app e scambia la memoria anonima per mantenerla entro il limite. A causa dell'espulsione e dello scambio, l'app potrebbe essere eseguita più lentamente.
In casi estremi, se l'app continua ad allocare memoria anonima e il dispositivo esaurisce lo spazio di swap, l'app potrebbe non riuscire ad allocare memoria e, di conseguenza, è probabile che si arresti in modo anomalo.
Monitoraggio dei processi
Per impostazione predefinita, Memory Limiter monitora i processi delle app (UID >= 10000). I processi di sistema sono generalmente esenti per contribuire a verificare la stabilità del sistema di base.
Memory Limiter assegna i limiti di memoria in base allo stato del processo:
I processi visibili sono in uno stato in cui possono mostrare un'interfaccia utente all'utente. Quando viene visualizzata un'interfaccia utente, è possibile che un processo utilizzi un set di lavoro RAM più grande, pertanto viene assegnato un limite di memoria più generoso.
I processi non visibili sono in uno stato in cui svolgono attivamente il lavoro, ma non disegnano un'interfaccia utente. Utilizzano la memoria per eseguire questo lavoro, ma meno di quanto necessario quando mostrano un'interfaccia utente, quindi viene assegnato un limite più restrittivo.
La tabella seguente associa gli stati dei processi specifici ai limiti di memoria:
| Stato elaborazione | Limite di memoria |
|---|---|
PERSISTENT | Senza restrizioni |
PERSISTENT_UI | Senza restrizioni |
TOP | Visibile |
BOUND_TOP | Visibile |
FOREGROUND_SERVICE | Non visibile |
BOUND_FOREGROUND_SERVICE | Non visibile |
IMPORTANT_FOREGROUND | Visibile |
IMPORTANT_BACKGROUND | Non visibile |
TRANSIENT_BACKGROUND | Non visibile |
BACKUP | Non visibile |
SERVICE | Non visibile |
RECEIVER | Non visibile |
TOP_SLEEPING | Visibile |
HEAVY_WEIGHT | Non visibile |
HOME | Non visibile |
LAST_ACTIVITY | Non visibile |
CACHED_ACTIVITY | Memorizzata nella cache |
CACHED_ACTIVITY_CLIENT | Memorizzata nella cache |
CACHED_RECENT | Memorizzata nella cache |
CACHED_EMPTY | Memorizzata nella cache |
Nello stato memorizzato nella cache, i processi vengono bloccati e poi recuperati al massimo.
Quando un processo supera il limite memory.high assegnato, Memory Limiter rileva l'evento e può attivare azioni di debug, ad esempio l'acquisizione di un profilo di memoria o la registrazione di un'anomalia in statsd.
Configurazione
Configura Memory Limiter utilizzando un file XML che si trova nella partizione vendor. La configurazione consente di ottimizzare i limiti di memoria assoluti in base ai vincoli di memoria specifici del dispositivo.
Percorso file:
/vendor/etc/memory-limiter-config.xmlConfigurazione predefinita: se il file di configurazione non viene trovato o se non è leggibile o valido, Memory Limiter viene disattivato.
XML
Il file di configurazione segue lo schema definito in memory-limiter-config.xsd. Il file consente di definire più set di limiti; il servizio sceglie la corrispondenza migliore in base alla RAM disponibile del dispositivo. Tutti i valori di memoria sono definiti in unità di mebibyte (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- Un numero intero positivo che identifica la versione di configurazione. Deve essere 1.
minimumRequiredMemTotal- La memoria di sistema disponibile minima richiesta per la validità di questo set di limiti.
memVisible- Il limite di memoria (
memory.high) consentito per i processi visibili. memNotVisible- Il limite di memoria (
memory.high) consentito per i processi non visibili. swapVisible- Il limite di swap (
memory.swap.max) consentito per i processi visibili. swapNotVisible- Il limite di swap (
memory.swap.max) consentito per i processi non visibili.
Linee guida per il limite di memoria del dispositivo
Quando configuri i limiti di memoria per il dispositivo, tieni presente le seguenti linee guida:
Adatta i limiti alle funzionalità hardware: gli OEM dei dispositivi possono impostare limiti personalizzati in base alle funzionalità hardware del dispositivo. Android consiglia i seguenti intervalli:
- Processi visibili: almeno 1/2 e al massimo 2/3 della RAM fisica totale.
- Processi non visibili: da 1/4 a 1/3 della RAM fisica totale. Gli OEM possono effettuare determinazioni diverse in base alle funzionalità e ai casi d'uso del dispositivo.
Nessuna API di runtime per le app: a partire da Android 17 (SDK 37), le app non hanno un'API per eseguire query sui limiti di memoria in fase di runtime. Gli OEM devono tenerne conto ed evitare di impostare limiti troppo bassi, assicurandosi che le app non raggiungano i limiti durante i casi d'uso ragionevoli.
Configurazione universale: i limiti si applicano a tutti i processi delle app sul dispositivo, incluse le app preinstallate. Non esiste una lista consentita per esentare determinate app da questi limiti.
Modifica della configurazione
Per modificare i limiti a livello di sistema:
- Modifica
/vendor/etc/memory-limiter-config.xml. - Riavvia il dispositivo o riavvia
system_serverper applicare le modifiche.
Comandi shell
Il comando am memory-limiter consente a te e agli sviluppatori di interagire con il servizio in fase di runtime per lo sviluppo e i test:
am memory-limiter <SUB-COMMAND>stato
Il sottocomando status segnala lo stato operativo di Memory Limiter:
adb shell am memory-limiter statusOutput di esempio:
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
I campi chiave nell'output includono:
monitoring- Indica se il limitatore sta monitorando attivamente i processi.
visibleMemenotVisibleMem- Indicano i limiti di memoria assoluti calcolati per ogni stato.
events- Il numero di volte in cui un processo ha superato il limite.
processes- Il numero di processi monitorati.
ignora
Il sottocomando ignore esclude temporaneamente un UID o tutti i processi dalla limitazione. Questa azione è utile per i test delle prestazioni o quando si consente a un'app specifica di superare i limiti.
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
manuale
Il sottocomando manual esegue l'override dei limiti calcolati per un processo specifico (in base all'ID processo o PID) con un valore assoluto personalizzato in megabyte (MB):
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
Gli override manuali si applicano solo al ciclo di vita del processo. Se il processo viene riavviato, torna ai limiti predefiniti in base al suo stato.