Limiteur de mémoire

Android 17 et versions ultérieures sont compatibles avec le Memory Limiter, un service système qui surveille et limite l'utilisation de la mémoire des processus d'application à l'aide de Linux cgroup v2. Le Memory Limiter 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 Memory Limiter 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 Memory Limiter applique les limites de mémoire à l'aide du système de fichiers cgroup v2 du noyau Linux.

Pour utiliser le Memory Limiter, 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 Memory Limiter.

Lorsqu'une application dépasse sa limite memory.high, le noyau supprime la mémoire de l'application sauvegardée dans un fichier 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 risque de ne pas pouvoir allouer de mémoire et, par conséquent, de planter.

Surveillance des processus

Par défaut, le Memory Limiter 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 Memory Limiter attribue des limites de mémoire en fonction de l'état du processus :

  • Les processus visibles sont dans un état où ils peuvent afficher une interface utilisateur à l'utilisateur. Lorsqu'il affiche une interface utilisateur, un processus peut être amené à utiliser un ensemble de travail RAM plus important. Il bénéficie donc d'une limite de mémoire plus généreuse.

  • Les processus non visibles sont dans un état où ils effectuent activement des tâches, mais n'affichent pas d'interface utilisateur. Ils utilisent de la mémoire pour effectuer ce travail, mais moins que lorsqu'ils affichent une interface utilisateur. Ils bénéficient donc d'une limite plus restrictive.

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 Memory Limiter 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 Memory Limiter à 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 Memory Limiter 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.

Consignes concernant la limite de mémoire de l'appareil

Lorsque vous configurez les limites de mémoire de votre appareil, tenez compte des consignes suivantes :

  • Adaptez les limites aux capacités matérielles : les OEM d'appareils peuvent définir des limites adaptées aux capacités matérielles de leurs appareils. Android recommande les plages suivantes :

    • Processus visibles : au moins 1/2 et au plus 2/3 de la RAM physique totale.
    • Processus non visibles : 1/4 à 1/3 de la RAM physique totale. Les OEM peuvent prendre des décisions différentes en fonction des capacités de l'appareil et des cas d'utilisation.
  • Aucune API d'exécution pour les applications : à partir d'Android 17 (SDK 37), les applications ne disposent pas d'API pour interroger les limites de mémoire au moment de l'exécution. Les OEM doivent en tenir compte et éviter de définir des limites trop basses, en veillant à ce que les applications n'atteignent pas les limites dans des cas d'utilisation raisonnables.

  • Configuration universelle : les limites s'appliquent à tous les processus d'application sur l'appareil, y compris les applications préinstallées. Il n'existe aucune liste d'autorisation pour exempter certaines applications de ces limites.

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 Memory Limiter :

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.