Android 17 y las 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 la aplicación con Linux cgroup v2. 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 falta de memoria (OOM) de los procesos críticos.
Mecanismos
El limitador de memoria se integra con el servicio de administrador de actividades (AMS) para hacer un seguimiento de los eventos del ciclo de vida del proceso y los cambios de estado. El limitador de memoria aplica los 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. El servicio se basa específicamente en los siguientes atributos:
memory.high- Es un límite flexible. Cuando se supera, se limita el proceso y el kernel intenta recuperar la memoria.
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 cambia su memoria anónima para mantener la app dentro del límite. Como resultado de la expulsión y el intercambio, es posible que la app se ejecute más lento.
En el extremo, si la app continúa 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 la app (UID >= 10000). Por lo general, los procesos del sistema están exentos para ayudar a verificar la estabilidad del sistema central.
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 proceso 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 en función de 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 configuración. Debe ser 1.
minimumRequiredMemTotal- Es la memoria mínima del sistema disponible requerida para que este conjunto de límites sea válido.
memVisible- Es el límite de memoria (
memory.high) permitido para los procesos visibles. memNotVisible- Es el límite de memoria (
memory.high) permitido para los procesos no visibles. swapVisible- Es el 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.
Modifica 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 los cambios tengan efecto.
Comandos del shell
El comando am memory-limiter te permite a ti y a los desarrolladores 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 lo siguiente:
monitoring- Indica si el limitador está observando procesos de forma activa.
visibleMemynotVisibleMem- Indican los límites de memoria absolutos calculados para cada estado.
events- Es la cantidad de veces que un proceso superó su límite.
processes- Es la cantidad de procesos supervisados.
ignore
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 el proceso se reinicia, vuelve a los límites predeterminados según su estado.