Android 17 e versioni successive includono 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 una quantità sproporzionata di memoria di sistema, riducendo la pressione complessiva sulla memoria e impedendo l'interruzione aggressiva per memoria insufficiente dei processi in primo piano e memorizzati nella cache critici.
Meccanismo
Il limitatore di memoria si integra con l'Activity Manager Service (AMS) per monitorare gli eventi del ciclo di vita dei processi e le modifiche di stato. Il limitatore di memoria applica i limiti di memoria utilizzando la gerarchia cgroup v2 del kernel Linux.
Per supportare il limitatore di memoria, il kernel del dispositivo deve abilitare cgroup v2 e il controller memory. Il servizio si basa in particolare sui seguenti attributi:
memory.high- Un limite flessibile. Se questo limite viene superato, il processo viene limitato e il kernel tenta il recupero proattivo delle pagine da quel processo.
memory.swap.max- Limita la quantità massima di spazio di swap (ad esempio ZRAM) che il processo può utilizzare.
Impatto sulle app
Le app che operano entro i limiti di memoria non sono interessate dal limitatore di memoria.
Quando un'app supera il limite di memory.high, il kernel rimuove la memoria pulita dell'app supportata da file e scambia la memoria anonima non attiva per mantenere l'app entro il limite. A seguito di questa attività di espulsione e scambio di pagine, l'app potrebbe subire una limitazione temporanea dell'esecuzione, ma continua a essere eseguita.
In situazioni estreme, ad esempio una perdita di memoria incontrollata in cui l'app continua ad allocare memoria anonima dopo l'esaurimento dello spazio di swap, l'app non riesce ad allocare memoria e viene terminata.
Monitoraggio dei processi
Per impostazione predefinita, il limitatore di memoria monitora i processi delle app (UID >= 10000). I processi di sistema principali sono esenti per preservare la stabilità essenziale del sistema.
Il limitatore di memoria assegna i limiti di memoria in base allo stato di visibilità del processo:
Processi visibili:processi che ospitano un'interfaccia utente visibile all'utente (ad esempio l'attività attualmente attiva o un'interazione attiva). Poiché la visualizzazione di una UI richiede un set di lavoro più ampio per il rendering e le pipeline grafiche, i processi visibili ricevono un limite di memoria più generoso.
Processi non visibili:processi che eseguono operazioni in background senza presentare un'interfaccia utente (ad esempio servizi in background o broadcast receiver). Poiché non eseguono il rendering dei componenti dell'interfaccia utente, operano con un limite più restrittivo.
La tabella seguente mappa stati di processo specifici alle classificazioni dei 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 di memory.high assegnato, il limitatore di memoria
rileva l'evento e può attivare azioni di diagnostica, come l'acquisizione di un
profilo di memoria o la registrazione di un'anomalia in statsd.
Configurazione
In Android 17 e versioni successive, il limitatore di memoria viene configurato utilizzando il file di configurazione della piattaforma standard nella partizione di sistema in /system/etc/memory-limiter-config.xml.
Formato XML
Il file di configurazione segue lo schema definito in memory-limiter-config.xsd. Il file definisce più set di limiti ordinati in base alla memoria disponibile. Il servizio seleziona il set di limiti corrispondente più alto in base alla RAM disponibile del dispositivo. Tutti i valori di memoria sono specificati in mebibyte (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- Un numero intero positivo che identifica la versione della configurazione. Deve essere
1. minimumRequiredMemTotalLa quantità minima di
MemTotaldi sistema (in MiB, valore minimo incluso) richiesta per l'applicazione di questo set di limiti. Il servizio valuta questo valore rispetto alla memoria totale disponibile indicata dal kernel in/proc/meminfo.Informazioni sulle suddivisioni e sui limiti della memoria:il valore del kernel
MemTotalriflette la DRAM fisica accessibile al sistema operativo dopo la detrazione delle suddivisioni della memoria hardware e firmware. Le partizioni riservano la RAM per componenti hardware specializzati come la GPU, il modem in banda base, l'ISP della fotocamera, gli ambienti di esecuzione sicuri e gli hypervisor, consumando in genere tra 500 MiB e oltre 2 GiB di memoria fisica.Poiché
MemTotalè inferiore alla DRAM fisica pubblicizzata del dispositivo, le soglie diminimumRequiredMemTotalincludono un margine per queste esclusioni. Ad esempio, una configurazione che ha come target dispositivi da 16 GB specifica un valore minimo di14336(14 GiB) anziché16384(16 GiB), mentre un livello per dispositivi da 12 GB specifica un valore minimo di9216(9 GiB). In questo modo, ogni dispositivo corrisponde al livello previsto, indipendentemente dalle variazioni di carve-out a livello di scheda.maximumAllowedMemTotalIl valore massimo di
MemTotaldi sistema (in MiB, limite esclusivo) per l'applicazione di questo set di limiti. SeMemTotalè maggiore o uguale a questo limite massimo, il limite impostato non viene applicato. Per i dispositivi con almeno 18.432 MiB o con meno di 3200 MiB, il limitatore di memoria non applica limiti, lasciando i processi senza vincoli.memVisibleIl limite di memoria flessibile (
memory.high) in MiB applicato ai processi visibili.memNotVisibleIl limite di memoria flessibile (
memory.high) in MiB applicato ai processi non visibili.swapVisibleIl limite di spazio di swap (
memory.swap.max) in MiB applicato ai processi visibili.swapNotVisibleIl limite dello spazio di swap (
memory.swap.max) in MiB applicato ai processi non visibili.
Limiti della piattaforma standard
In Android 17 e versioni successive, la piattaforma specifica i limiti di memoria e swap standard in /system/etc/memory-limiter-config.xml per i livelli di RAM fisica comuni utilizzando gli intervalli di intervallo [floor, ceiling):
| RAM fisica target |
Intervallo MemTotal [minimo, massimo) (minimumRequiredMemTotal, maximumAllowedMemTotal) |
Limite di memoria visibile (memVisible) |
Limite di memoria non visibile (memNotVisible) |
Limite di scambio visibile (swapVisible) |
Limite di scambio non visibile (swapNotVisible) |
|---|---|---|---|---|---|
| 16 GB | [14336, 18432) MiB |
10.240 MiB (10 GiB) | 5120 MiB (5 GiB) | 5120 MiB (5 GiB) | 5120 MiB (5 GiB) |
| 12 GB | [9216, 14336) MiB |
8192 MiB (8 GiB) | 4096 MiB (4 GiB) | 4096 MiB (4 GiB) | 4096 MiB (4 GiB) |
| 8 GB | [6800, 9216) MiB |
5120 MiB (5 GiB) | 3072 MiB (3 GiB) | 3072 MiB (3 GiB) | 3072 MiB (3 GiB) |
| 6 GB | [4800, 6800) MiB |
4096 MiB (4 GiB) | 2048 MiB (2 GiB) | 2048 MiB (2 GiB) | 2048 MiB (2 GiB) |
| 4 GB | [3200, 4800) MiB |
2048 MiB (2 GiB) | 1024 MiB (1 GiB) | 1024 MiB (1 GiB) | 1024 MiB (1 GiB) |
Principi dei limiti di memoria
La configurazione del limitatore di memoria è progettata in base ai seguenti principi della piattaforma:
Coerenza dell'ecosistema e compatibilità delle app:limiti di memoria coerenti su tutti i dispositivi garantiscono prestazioni delle app prevedibili in tutto l'ecosistema Android. Le app vengono sviluppate e testate in base alle aspettative di memoria standard; il mantenimento di limiti uniformi della piattaforma evita limitazioni impreviste o terminazioni premature.
Allocazione proporzionale delle risorse: i limiti della piattaforma sono calibrati in base alla capacità della RAM fisica:
- Processi visibili: viene allocata circa la metà o i due terzi della RAM fisica totale per supportare i workload attivi di UI, composizione e rendering.
- Processi non visibili:viene allocato circa 1/4-1/3 della RAM fisica totale per le attività in background.
Applicabilità universale:i limiti si applicano in modo uniforme a tutti i processi delle applicazioni sul dispositivo (UID >= 10000), incluse le app di sistema e OEM preinstallate. Il limitatore di memoria non supporta le liste consentite per esentare app specifiche, garantendo una gestione equa della memoria in tutte le app. Per configurare i floor di protezione con ottimizzazione automatica di
memory.minsui daemon interattivi critici e i ceiling più rigidi calibrati sul workload dimemory.highsu singole app e servizi di sistema, consulta Budget di memoria di sistema.Assenza di API di query di runtime:in Android 17 e versioni successive, le app non possono eseguire query in modo programmatico sui limiti di memoria assegnati in fase di runtime. I limiti standard della piattaforma sono definiti con margini generosi, in modo che le app con un comportamento corretto funzionino senza vincoli durante il normale utilizzo.
Dinamiche di recupero e scambio del kernel:quando un processo dell'app si avvicina al limite di
memory.high, il kernel Linux indirizza il recupero della memoria in modo specifico al cgroup di quel processo. Ciò include l'eliminazione delle pagine inattive supportate da file e lo scambio di pagine anonime non utilizzate con ZRAM, mantenendo la fluidità del sistema senza imporre una pressione della memoria globale.
Comandi shell
Il comando am memory-limiter consente agli sviluppatori e agli integratori di sistemi di interagire con il servizio in fase di runtime per lo sviluppo, i test e il debug:
am memory-limiter <SUB-COMMAND>stato
Il sottocomando status segnala lo stato di attività e le metriche attive del limitatore di memoria:
adb shell am memory-limiter statusDi seguito è riportato un esempio di output:
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 di memoria sta monitorando attivamente i processi.
visibleMemenotVisibleMem- I limiti di memoria assoluti calcolati (
memory.high) attualmente applicati per ogni stato di visibilità. visibleSwapenotVisibleSwap- I limiti di scambio assoluti calcolati (
memory.swap.max) attualmente applicati per ogni stato di visibilità. events- Il numero di volte in cui un processo ha superato il limite assegnato.
processes- Il numero attuale di processi monitorati.
ignora
Il sottocomando ignore esclude temporaneamente un UID specifico o tutti i processi dalla limitazione della memoria. Questo è utile per il benchmarking delle prestazioni, gli stress test o la diagnosi del comportamento della memoria:
# 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
manuale
Il sottocomando manual esegue l'override dei limiti calcolati per un processo specifico in base all'ID di processo (PID) con un valore assoluto personalizzato in byte. Il valore deve essere un numero intero, ma può includere il suffisso MB per indicare MiB o il suffisso GB per indicare 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
Gli override manuali si applicano solo alla durata di quella specifica istanza di processo. Se il processo viene riavviato, torna ai limiti standard in base al suo stato.
Un override manuale non può superare i limiti fisici dell'impianto.