Android 17 et versions ultérieures incluent 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 une quantité disproportionnée de mémoire système, ce qui réduit la pression globale sur la mémoire et empêche les suppressions agressives de mémoire faible des processus critiques au premier plan et mis en cache.
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 de la hiérarchie Linux kernel cgroup v2.
Pour prendre en charge le Memory Limiter, le noyau de l'appareil doit activer cgroup v2 et le contrôleur memory. Le service repose spécifiquement sur les attributs suivants :
memory.high- Limite flexible. En cas de dépassement, le processus est limité et le noyau tente de récupérer de manière proactive la page de ce processus.
memory.swap.max- Limite la quantité maximale d'espace d'échange (tel que ZRAM) que le processus peut utiliser.
Impact sur les applications
Les applications qui fonctionnent dans les limites de leur 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 propre de l'application et échange sa mémoire anonyme inactive pour que l'application reste dans la limite. En raison de cette suppression de page et de cette activité d'échange, l'application peut subir une limitation temporaire de l'exécution, mais elle continue de s'exécuter.
Dans des situations extrêmes, telles qu'une fuite de mémoire incontrôlée où l'application continue d'allouer de la mémoire anonyme une fois l'espace d'échange épuisé, l'application ne parvient pas à allouer de la mémoire et est arrêtée.
Surveillance des processus
Le Memory Limiter surveille les processus d'application (UID >= 10000) par défaut. Les processus système principaux sont exemptés afin de préserver la stabilité essentielle du système.
Le Memory Limiter attribue des limites de mémoire en fonction de l'état de visibilité du processus :
Processus visibles : processus hébergeant une interface utilisateur visible par l'utilisateur (telle que l'activité actuellement ciblée ou une interaction active). Étant donné que l'affichage d'une interface utilisateur nécessite un ensemble de travail plus important pour le rendu et les pipelines graphiques, les processus visibles bénéficient d'une limite de mémoire plus généreuse.
Processus non visibles : processus effectuant des tâches en arrière-plan sans présenter d'interface utilisateur (tels que les services en arrière-plan ou les récepteurs de diffusion). Comme ils ne rendent pas les composants de l'interface utilisateur, ils fonctionnent avec une limite plus restrictive.
Le tableau suivant mappe des états de processus spécifiques à des classifications de limites de mémoire :
| État du processus | Limite de mémoire |
|---|---|
PERSISTENT | Pas de restriction |
PERSISTENT_UI | Pas de restriction |
TOP | Visible |
BOUND_TOP | Visible |
FOREGROUND_SERVICE | Non visible |
BOUND_FOREGROUND_SERVICE | Non visible |
IMPORTANT_FOREGROUND | Visible |
IMPORTANT_BACKGROUND | Non visible |
TRANSIENT_BACKGROUND | Non visible |
BACKUP | Non visible |
SERVICE | Non visible |
RECEIVER | Non visible |
TOP_SLEEPING | Visible |
HEAVY_WEIGHT | Non visible |
HOME | Non visible |
LAST_ACTIVITY | Non visible |
CACHED_ACTIVITY | En cache |
CACHED_ACTIVITY_CLIENT | En cache |
CACHED_RECENT | En cache |
CACHED_EMPTY | En 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 diagnostic, telles que la capture d'un profil de mémoire ou la journalisation d'une anomalie dans statsd.
Configuration
Dans Android 17 et versions ultérieures, le Memory Limiter est configuré à l'aide du fichier de configuration de plate-forme standard sur la partition système à l'adresse /system/etc/memory-limiter-config.xml.
Format XML
Le fichier de configuration suit le schéma défini dans memory-limiter-config.xsd. Le fichier définit plusieurs ensembles de limites classés par mémoire disponible. Le service sélectionne l'ensemble de limites correspondant le plus élevé en fonction de la RAM disponible de l'appareil. Toutes les valeurs de mémoire sont spécifiées en mébioctets (Mio).
<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- Entier positif identifiant la version de configuration. Doit être
1. minimumRequiredMemTotalSystème
MemTotalminimal (en Mio, plancher inclus) requis pour que cet ensemble de limites s'applique. Le service évalue cela par rapport à la mémoire totale disponible signalée par le noyau dans/proc/meminfo.Comprendre les limites et les limites de mémoire : la valeur
MemTotaldu noyau reflète la DRAM physique accessible au système d'exploitation après déduction des limites de mémoire matérielles et micrologicielles. Les limites réservent de la RAM pour des composants matériels spécialisés tels que le GPU, le modem de bande de base, l'ISP de la caméra, les environnements d'exécution sécurisés et les hyperviseurs, consommant généralement entre 500 Mio et plus de 2 Gio de mémoire physique.Étant donné que
MemTotalest inférieur à la DRAM physique annoncée de l'appareil,minimumRequiredMemTotalseuils incluent une marge pour ces limites. Par exemple, une configuration ciblant les appareils de 16 Go spécifie un plancher de14336(14 Gio) au lieu de16384(16 Gio), et un niveau pour les appareils de 12 Go spécifie un plancher de9216(9 Gio). Cela garantit que chaque appareil correspond au niveau prévu, quelles que soient les variations de limites au niveau de la carte.maximumAllowedMemTotalSystème
MemTotalmaximal (en Mio, plafond exclusif) pour que cet ensemble de limites s'applique. SiMemTotalest supérieur ou égal à ce plafond, l'ensemble de limites ne s'applique pas. Pour les appareils avec 18 432 Mio ou plus, ou pour les appareils avec moins de 3 200 Mio, le Memory Limiter n'applique pas de limites, ce qui laisse les processus sans contrainte.memVisibleLimite de mémoire flexible (
memory.high) en Mio appliquée aux processus visibles.memNotVisibleLimite de mémoire flexible (
memory.high) en Mio appliquée aux processus non visibles.swapVisibleLimite d'espace d'échange (
memory.swap.max) en Mio appliquée aux processus visibles.swapNotVisibleLimite d'espace d'échange (
memory.swap.max) en Mio appliquée aux processus non visibles.
Limites de plate-forme standards
Dans Android 17 et versions ultérieures, la plate-forme spécifie des limites de mémoire et d'échange standards dans /system/etc/memory-limiter-config.xml sur les niveaux de RAM physique courants à l'aide d'intervalles de plage [floor, ceiling) :
| RAM physique cible |
Plage MemTotal [plancher, plafond) (minimumRequiredMemTotal, maximumAllowedMemTotal) |
Limite de mémoire visible (memVisible) |
Limite de mémoire non visible (memNotVisible) |
Limite d'échange visible (swapVisible) |
Limite d'échange non visible (swapNotVisible) |
|---|---|---|---|---|---|
| 16 Go | [14336, 18432) Mio |
10 240 Mio (10 Gio) | 5 120 Mio (5 Gio) | 5 120 Mio (5 Gio) | 5 120 Mio (5 Gio) |
| 12 Go | [9216, 14336) Mio |
8 192 Mio (8 Gio) | 4 096 Mio (4 Gio) | 4 096 Mio (4 Gio) | 4 096 Mio (4 Gio) |
| 8 Go | [6800, 9216) Mio |
5 120 Mio (5 Gio) | 3 072 Mio (3 Gio) | 3 072 Mio (3 Gio) | 3 072 Mio (3 Gio) |
| 6 Go | [4800, 6800) Mio |
4 096 Mio (4 Gio) | 2 048 Mio (2 Gio) | 2 048 Mio (2 Gio) | 2 048 Mio (2 Gio) |
| 4 Go | [3200, 4800) Mio |
2 048 Mio (2 Gio) | 1 024 Mio (1 Gio) | 1 024 Mio (1 Gio) | 1 024 Mio (1 Gio) |
Principes de limite de mémoire
La configuration du Memory Limiter est conçue autour des principes de plate-forme suivants :
Cohérence de l'écosystème et compatibilité des applications : des limites de mémoire cohérentes sur tous les appareils garantissent des performances d'application prévisibles dans l'ensemble de l'écosystème Android. Les applications sont développées et testées par rapport aux attentes de mémoire standards. Le maintien de limites de plate-forme uniformes évite les limitations inattendues ou les arrêts prématurés.
Allocation proportionnelle des ressources : les limites de la plate-forme sont calibrées en fonction de la capacité de la RAM physique :
- Processus visibles : environ 1/2 à 2/3 de la RAM physique totale allouée pour prendre en charge les charges de travail d'interface utilisateur, de composition et de rendu actives.
- Processus non visibles : environ 1/4 à 1/3 de la RAM physique totale allouée pour les tâches en arrière-plan.
Applicabilité universelle : les limites s'appliquent de manière uniforme à tous les processus d'application sur l'appareil (UID >= 10000), y compris les applications système et OEM préinstallées. Le Memory Limiter ne prend pas en charge les listes d'autorisation pour exempter des applications spécifiques, ce qui garantit une gestion équitable de la mémoire dans toutes les applications.
Absence d'API de requête d'exécution : dans Android 17 et versions ultérieures, les applications ne peuvent pas interroger par programmation les limites de mémoire qui leur sont attribuées au moment de l'exécution. Les limites de plate-forme standards sont définies avec des marges généreuses afin que les applications bien comportées fonctionnent sans contrainte lors d'une utilisation normale.
Récupération du noyau et dynamique d'échange : lorsqu'un processus d'application approche de sa limite
memory.high, le noyau Linux dirige la récupération de mémoire spécifiquement vers ce cgroup de processus. Cela inclut la suppression des pages sauvegardées inactives et l'échange des pages anonymes froides vers ZRAM, ce qui maintient la fluidité du système sans imposer de pression globale sur la mémoire.
Commandes shell
La commande am memory-limiter permet aux développeurs et aux intégrateurs système d'interagir avec le service au moment de l'exécution pour le développement, les tests et le débogage :
am memory-limiter <SUB-COMMAND>état
La sous-commande status indique l'état opérationnel et les métriques actives du Memory Limiter :
adb shell am memory-limiter statusVoici un 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 Memory Limiter surveille activement les processus.
visibleMemetnotVisibleMem- Limites de mémoire absolues calculées (
memory.high) actuellement appliquées pour chaque état de visibilité. visibleSwapetnotVisibleSwap- Limites d'échange absolues calculées (
memory.swap.max) actuellement appliquées pour chaque état de visibilité. events- Nombre de fois qu'un processus a dépassé sa limite attribuée.
processes- Nombre actuel de processus surveillés.
ignorer
La sous-commande ignore exclut temporairement un UID spécifique ou tous les processus de la limitation de mémoire. Cela est utile pour l'analyse comparative des performances, les tests de résistance ou le diagnostic du comportement de la mémoire :
# 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
manuel
La sous-commande manual remplace les limites calculées pour un processus spécifique par un ID de processus (PID) avec une valeur absolue personnalisée en octets. La valeur doit être un entier, mais peut inclure le suffixe MB pour indiquer Mio ou le suffixe GB pour indiquer Gio :
# 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
Les remplacements manuels ne s'appliquent que pendant la durée de vie de cette instance de processus spécifique. Si le processus redémarre, il revient aux limites standards en fonction de son état.
Un remplacement manuel ne peut pas dépasser les limites physiques du système.