Android 17 e versioni successive supportano il limitatore di memoria, un servizio di sistema che monitora e limita la memoria utilizzata dei processi delle applicazioni utilizzando cgroup v2 di Linux. Il limitatore di memoria impedisce alle singole app di consumare troppa memoria di sistema, il che riduce la pressione della memoria a livello di sistema e impedisce l'interruzione aggressiva per esaurimento della memoria (OOM) dei processi critici.
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. Il limite di memoria applica limiti di memoria utilizzando il file system cgroup v2 del kernel Linux.
Per utilizzare il limite di memoria, 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 dal limite di memoria.
Quando un'app supera il limite di memory.high, il kernel espelle la memoria basata su file dell'app e scambia la memoria anonima per mantenere l'app entro il limite. A seguito 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, il limite di memoria monitora i processi delle app (UID >= 10000). I processi di sistema sono generalmente esenti per contribuire a verificare la stabilità del sistema principale.
Il limite di memoria assegna limiti di memoria in base allo stato del processo:
I processi visibili sono percepibili dall'utente, ad esempio attività in primo piano, servizi in primo piano o altri stati percepibili come jank.
I processi non visibili sono processi in background che non interagiscono con l'utente e non sono visibili.
La tabella seguente mappa stati specifici del processo 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 acquisire un profilo di memoria o registrare un'anomalia in statsd.
Configurazione
Configura il limite di memoria utilizzando un file XML che si trova nella partizione vendor. La configurazione ti 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, il limite di memoria viene disattivato.
Formato XML
Il file di configurazione segue lo schema definito in
memory-limiter-config.xsd. Il file ti 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 della configurazione. Deve essere 1.
minimumRequiredMemTotal- La memoria di sistema disponibile minima richiesta per la validità di questo limite impostato.
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.
Modifica configurazione
Per modificare i limiti a livello di sistema:
- Modifica
/vendor/etc/memory-limiter-config.xml. - Riavvia il dispositivo o
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 esecuzione per lo sviluppo e il test:
am memory-limiter <SUB-COMMAND>stato
Il sottocomando status segnala lo stato operativo del limite di memoria:
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 limite sta monitorando attivamente i processi.
visibleMemenotVisibleMem- Indica 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 dall'applicazione di limiti. 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 sostituisce i limiti calcolati per un processo specifico (in base all'ID di 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.