Android 17 y versiones posteriores admiten el limitador de memoria, que es un servicio del sistema que supervisa y limita el uso de memoria de los procesos de aplicaciones con cgroup v2 de Linux. El limitador de memoria evita que las apps individuales consuman demasiada memoria del sistema, lo que reduce la presión de la memoria en todo el sistema y evita la finalización agresiva por memoria insuficiente (OOM) de procesos críticos.
Mecanismos
El limitador de memoria se integra con el servicio de Activity Manager (AMS) para hacer un seguimiento de los eventos del ciclo de vida del proceso y los cambios de estado. El limitador de memoria aplica límites de memoria con el sistema de archivos cgroup v2 del kernel de Linux.
Para usar el limitador de memoria, el kernel del dispositivo debe admitir cgroup v2 y el controlador memory. Específicamente, el servicio se basa en los siguientes atributos:
memory.high- Es un límite flexible. Cuando se supera, se limita el proceso y el kernel intenta recuperar memoria de él.
memory.swap.max- Limita la cantidad de espacio de intercambio que puede usar el proceso.
Impacto en las apps
El Limitador de memoria no afecta a las apps que no superan sus límites de memoria.
Cuando una app supera su límite de memory.high, el kernel expulsa la memoria respaldada por archivos de la app y permuta su memoria anónima para mantener la app dentro del límite. Como resultado del desalojo y el intercambio, es posible que la app se ejecute más lento.
En el peor de los casos, si la app sigue asignando memoria anónima y el dispositivo se queda sin espacio de intercambio, es posible que la app no pueda asignar memoria y, como resultado, es probable que falle.
Supervisión de procesos
De forma predeterminada, el Limitador de memoria supervisa los procesos de las apps (UID >= 10000). Por lo general, los procesos del sistema están exentos para ayudar a verificar la estabilidad del sistema principal.
El limitador de memoria asigna límites de memoria según el estado del proceso:
Los procesos visibles son perceptibles para el usuario, como las actividades en primer plano, los servicios en primer plano o cualquier otro estado perceptible de jank.
Los procesos no visibles son procesos en segundo plano que no interactúan con el usuario ni son visibles para él.
En la siguiente tabla, se asignan estados de procesos específicos a límites de memoria:
| Estado del proceso | Límite de memoria |
|---|---|
PERSISTENT | Sin restricciones |
PERSISTENT_UI | Sin restricciones |
TOP | Visible |
BOUND_TOP | Visible |
FOREGROUND_SERVICE | No visible |
BOUND_FOREGROUND_SERVICE | No visible |
IMPORTANT_FOREGROUND | Visible |
IMPORTANT_BACKGROUND | No visible |
TRANSIENT_BACKGROUND | No visible |
BACKUP | No visible |
SERVICE | No visible |
RECEIVER | No visible |
TOP_SLEEPING | Visible |
HEAVY_WEIGHT | No visible |
HOME | No visible |
LAST_ACTIVITY | No visible |
CACHED_ACTIVITY | Almacenado en caché |
CACHED_ACTIVITY_CLIENT | Almacenado en caché |
CACHED_RECENT | Almacenado en caché |
CACHED_EMPTY | Almacenado en caché |
En el estado almacenado en caché, los procesos se congelan y, luego, se recuperan al máximo.
Cuando un proceso supera el límite de memory.high asignado, el limitador de memoria detecta el evento y puede activar acciones de depuración, como capturar un perfil de memoria o registrar una anomalía en statsd.
Configuración
Configura el limitador de memoria con un archivo en formato XML ubicado en la partición vendor. La configuración te permite ajustar los límites de memoria absolutos según las restricciones de memoria específicas del dispositivo.
Ruta de acceso al archivo:
/vendor/etc/memory-limiter-config.xmlConfiguración predeterminada: Si no se encuentra el archivo de configuración o si no se puede leer o no es válido, se inhabilita el limitador de memoria.
Formato XML
El archivo de configuración sigue el esquema definido en memory-limiter-config.xsd. El archivo te permite definir varios conjuntos de límites. El servicio elige la mejor coincidencia según la RAM disponible del dispositivo. Todos los valores de memoria se definen en unidades de mebibytes (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- Es un número entero positivo que identifica la versión de la configuración. Debe ser 1.
minimumRequiredMemTotal- Es la memoria del sistema disponible mínima requerida para que este límite sea válido.
memVisible- Límite de memoria (
memory.high) permitido para los procesos visibles. memNotVisible- Límite de memoria (
memory.high) permitido para los procesos no visibles. swapVisible- Límite de intercambio (
memory.swap.max) permitido para los procesos visibles. swapNotVisible- Es el límite de intercambio (
memory.swap.max) permitido para los procesos no visibles.
Lineamientos sobre el límite de memoria del dispositivo
Cuando configures los límites de memoria para tu dispositivo, ten en cuenta los siguientes lineamientos:
Límites personalizados según las capacidades del hardware: Los OEM de dispositivos pueden establecer límites personalizados según las capacidades del hardware de sus dispositivos. Android recomienda los siguientes rangos:
- Procesos visibles: Al menos 1/2 y, como máximo, 2/3 de la RAM física total.
- Procesos no visibles: De 1/4 a 1/3 de la RAM física total Los OEM pueden tomar diferentes determinaciones según las capacidades y los casos de uso del dispositivo.
No hay API de tiempo de ejecución para las apps: A partir de Android 17 (SDK 37), las apps no tienen una API para consultar los límites de memoria en el tiempo de ejecución. Los OEM deben tener esto en cuenta y evitar establecer límites demasiado bajos, lo que garantiza que las apps no alcancen los límites durante los casos de uso razonables.
Configuración universal: Los límites se aplican a todos los procesos de la app en el dispositivo, incluidas las apps preinstaladas. No hay una lista de entidades permitidas para eximir a ciertas apps de estos límites.
Modificar la configuración
Para cambiar los límites en todo el sistema, sigue estos pasos:
- Modifica
/vendor/etc/memory-limiter-config.xml. - Reinicia el dispositivo o
system_serverpara que se apliquen los cambios.
Comandos del shell
El comando am memory-limiter te permite interactuar con el servicio en tiempo de ejecución para el desarrollo y las pruebas:
am memory-limiter <SUB-COMMAND>estado
El subcomando status informa el estado operativo del Limitador de memoria:
adb shell am memory-limiter statusResultado de ejemplo:
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
Los campos clave en el resultado incluyen los siguientes:
monitoring- Indica si el limitador está supervisando activamente los procesos.
visibleMemynotVisibleMem- Indica los límites de memoria absolutos calculados para cada estado.
events- Cantidad de veces que un proceso superó su límite.
processes- Es la cantidad de procesos supervisados.
Ignorar
El subcomando ignore excluye temporalmente un UID o todos los procesos de la limitación. Esta acción es útil para las pruebas de rendimiento o cuando se permite que una app específica supere sus límites.
adb shell am memory-limiter ignore 10087 // Ignore a specific UIDadb shell am memory-limiter ignore all // Ignore all processes (effectively disables limiting)adb shell am memory-limiter ignore none // Resume normal operation
manual
El subcomando manual anula los límites calculados para un proceso específico (por ID de proceso o PID) con un valor absoluto personalizado en megabytes (MB):
adb shell am memory-limiter manual 1234 1024 // Set a 1024 MB limit for PID 1234adb shell am memory-limiter manual 1234 none // Remove the manual override for PID 1234
Las anulaciones manuales solo se aplican al ciclo de vida del proceso. Si se reinicia el proceso, se restablecen los límites predeterminados según su estado.