Limiteur de mémoire

Android 17 et versions ultérieures sont compatibles avec le limiteur de mémoire, un service système qui surveille et limite l'utilisation de la mémoire des processus d'application à l'aide de cgroup v2 Linux. Le limiteur de mémoire empêche les applications individuelles de consommer trop de mémoire système, ce qui réduit la pression sur la mémoire à l'échelle du système et empêche l'arrêt agressif des processus critiques en cas de mémoire insuffisante (OOM).

Mécanisme

Le limiteur de mémoire s'intègre au service Activity Manager (AMS) pour suivre les événements du cycle de vie des processus et les changements d'état. Le limiteur de mémoire applique les limites de mémoire à l'aide du système de fichiers cgroup v2 du noyau Linux.

Pour utiliser le limiteur de mémoire, le noyau de l'appareil doit être compatible avec cgroup v2 et le contrôleur memory. Le service repose spécifiquement sur les attributs suivants :

memory.high
Limite flexible. Lorsqu'elle est dépassée, le processus est limité et le noyau tente de récupérer de la mémoire.
memory.swap.max
Limite la quantité d'espace d'échange que le processus peut utiliser.

Impact sur les applications

Les applications qui ne dépassent pas leurs limites de mémoire ne sont pas affectées par le limiteur de mémoire.

Lorsqu'une application dépasse sa limite memory.high, le noyau supprime la mémoire sauvegardée de l'application et échange sa mémoire anonyme pour que l'application reste dans la limite. En raison de la suppression et de l'échange, l'application peut s'exécuter plus lentement.

À l'extrême, si l'application continue d'allouer de la mémoire anonyme et que l'appareil manque d'espace d'échange, l'application peut ne pas parvenir à allouer de la mémoire et risque donc de planter.

Surveillance des processus

Par défaut, le limiteur de mémoire surveille les processus d'application (UID >= 10000). Les processus système sont généralement exemptés pour aider à vérifier la stabilité du système de base.

Le limiteur de mémoire attribue des limites de mémoire en fonction de l'état du processus :

  • Les processus visibles sont perceptibles par l'utilisateur, comme les activités de premier plan, les services de premier plan ou d'autres états perceptibles.

  • Les processus non visibles sont des processus d'arrière-plan qui n'interagissent pas avec l'utilisateur et ne sont pas visibles par lui.

Le tableau suivant mappe des états de processus spécifiques à des limites de mémoire :

État du processusLimite de mémoire
PERSISTENTPas de restriction
PERSISTENT_UIPas de restriction
TOPVisible
BOUND_TOPVisible
FOREGROUND_SERVICENon visible
BOUND_FOREGROUND_SERVICENon visible
IMPORTANT_FOREGROUNDVisible
IMPORTANT_BACKGROUNDNon visible
TRANSIENT_BACKGROUNDNon visible
BACKUPNon visible
SERVICENon visible
RECEIVERNon visible
TOP_SLEEPINGVisible
HEAVY_WEIGHTNon visible
HOMENon visible
LAST_ACTIVITYNon visible
CACHED_ACTIVITYEn cache
CACHED_ACTIVITY_CLIENTEn cache
CACHED_RECENTEn cache
CACHED_EMPTYEn cache

Dans l'état mis en cache, les processus sont figés, puis récupérés au maximum.

Lorsqu'un processus dépasse sa limite memory.high attribuée, le limiteur de mémoire détecte l'événement et peut déclencher des actions de débogage, telles que la capture d'un profil de mémoire ou la journalisation d'une anomalie dans statsd.

Configuration

Configurez le limiteur de mémoire à l'aide d'un fichier XML situé sur la partition vendor. La configuration vous permet d'ajuster les limites de mémoire absolues en fonction des contraintes de mémoire spécifiques de l'appareil.

  • Chemin d'accès au fichier : /vendor/etc/memory-limiter-config.xml

  • Configuration par défaut : si le fichier de configuration est introuvable, illisible ou non valide, le limiteur de mémoire est désactivé.

Format XML

Le fichier de configuration suit le schéma défini dans memory-limiter-config.xsd. Le fichier vous permet de définir plusieurs ensembles de limites. Le service choisit la meilleure correspondance en fonction de la RAM disponible de l'appareil. Toutes les valeurs de mémoire sont définies en mébioctets (Mio).

<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
Entier positif identifiant la version de configuration. Doit être égal à 1.
minimumRequiredMemTotal
Mémoire système disponible minimale requise pour que cet ensemble de limites soit valide.
memVisible
Limite de mémoire (memory.high) autorisée pour les processus visibles.
memNotVisible
Limite de mémoire (memory.high) autorisée pour les processus non visibles.
swapVisible
Limite d'échange (memory.swap.max) autorisée pour les processus visibles.
swapNotVisible
Limite d'échange (memory.swap.max) autorisée pour les processus non visibles.

Modifier la configuration

Pour modifier les limites à l'échelle du système, procédez comme suit :

  1. Modifiez /vendor/etc/memory-limiter-config.xml.
  2. Redémarrez l'appareil ou redémarrez system_server pour que les modifications prennent effet.

Commandes shell

La commande am memory-limiter vous permet, ainsi qu'aux développeurs, d'interagir avec le service au moment de l'exécution pour le développement et les tests :

am memory-limiter <SUB-COMMAND>

état

La sous-commande status indique l'état opérationnel du limiteur de mémoire :

adb shell am memory-limiter status

Exemple de résultat :

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

Les champs clés du résultat incluent les suivants :

monitoring
Indique si le limiteur surveille activement les processus.
visibleMem et notVisibleMem
Indiquent les limites de mémoire absolues calculées pour chaque état.
events
Nombre de fois qu'un processus a dépassé sa limite.
processes
Nombre de processus surveillés.

ignorer

La sous-commande ignore exclut temporairement un UID ou tous les processus de la limitation. Cette action est utile pour les tests de performances ou lorsque vous autorisez une application spécifique à dépasser ses limites.

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

manuel

La sous-commande manual remplace les limites calculées pour un processus spécifique (par ID de processus ou PID) par une valeur absolue personnalisée en mégaoctets (Mo) :

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

Les remplacements manuels ne s'appliquent qu'au cycle de vie du processus. Si le processus redémarre, il revient aux limites par défaut en fonction de son état.