Limitatore di memoria

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 elaborazioneLimite di memoria
PERSISTENTSenza restrizioni
PERSISTENT_UISenza restrizioni
TOPVisibile
BOUND_TOPVisibile
FOREGROUND_SERVICENon visibile
BOUND_FOREGROUND_SERVICENon visibile
IMPORTANT_FOREGROUNDVisibile
IMPORTANT_BACKGROUNDNon visibile
TRANSIENT_BACKGROUNDNon visibile
BACKUPNon visibile
SERVICENon visibile
RECEIVERNon visibile
TOP_SLEEPINGVisibile
HEAVY_WEIGHTNon visibile
HOMENon visibile
LAST_ACTIVITYNon visibile
CACHED_ACTIVITYMemorizzata nella cache
CACHED_ACTIVITY_CLIENTMemorizzata nella cache
CACHED_RECENTMemorizzata nella cache
CACHED_EMPTYMemorizzata 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.xml

  • Configurazione 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:

  1. Modifica /vendor/etc/memory-limiter-config.xml.
  2. Riavvia il dispositivo o system_server per 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 status

Output 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.
visibleMem e notVisibleMem
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 UID
adb 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 1234
adb 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.