Daemon optimizador de poca memoria

El proceso del daemon de optimización de poca memoria de Android (lmkd) supervisa el estado de la memoria de un sistema Android en ejecución y reacciona a la presión de memoria alta cerrando los procesos menos esenciales para mantener el rendimiento del sistema en niveles aceptables.

Información acerca de la presión de la memoria

Un sistema Android que ejecuta varios procesos en paralelo puede encontrar situaciones en las que se agota la memoria del sistema y los procesos que requieren más memoria experimentan demoras notables. La presión de memoria, un estado en el que el sistema se queda sin memoria, requiere que Android libere memoria (para aliviar la presión) regulando o finalizando procesos no importantes, solicitando procesos para liberar recursos almacenados en caché no críticos, y así sucesivamente.

Históricamente, Android supervisaba la presión de memoria del sistema mediante un controlador optimizado de memoria baja (LMK) del kernel, un mecanismo rígido que depende de valores hard-coded. A partir del kernel 4.12, se quita el controlador de LMK del kernel upstream y el espacio del usuario lmkd realiza tareas de supervisión de memoria y finalización de procesos.

Información sobre la detención por presión

Android 10 y versiones posteriores admiten un nuevo modo lmkd que usa monitores de información de demora de presión (PSI) del kernel para la detección de presión de la memoria. El conjunto de parches de PSI en el kernel upstream (portado a los kernels 4.9 y 4.14) mide la cantidad de tiempo que se retrasan las tareas como resultado de la escasez de memoria. Como estas demoras afectan directamente la experiencia del usuario, representan una métrica conveniente para determinar la gravedad de la presión de la memoria. El kernel ascendente también incluye monitores PSI que permiten que los procesos de espacio del usuario con privilegios (como lmkd) especifiquen umbrales para estas demoras y se suscriban a eventos del kernel cuando se incumpla un umbral.

Monitores de PSI en comparación con los indicadores de vmpressure

Debido a que los indicadores vmpressure (que genera el kernel para la detección de presión de memoria y que usa lmkd) suelen incluir numerosos falsos positivos, lmkd debe realizar un filtrado para determinar si la memoria está bajo presión real. Esto genera activaciones innecesarias de lmkd y el uso de recursos de procesamiento adicionales. El uso de monitores de PSI genera una detección de presión de memoria más precisa y minimiza la sobrecarga de filtrado.

Usa monitores de PSI

Para usar monitores de PSI en lugar de eventos vmpressure, configura la propiedad ro.lmk.use_psi. El valor predeterminado es true, lo que hace que los monitores de PSI sean el mecanismo predeterminado de detección de presión de la memoria para lmkd. Debido a que los monitores de PSI requieren compatibilidad con el kernel, este debe incluir los parches de portabilidad a versiones anteriores de PSI y compilarse con la compatibilidad con PSI habilitada (CONFIG_PSI=y).

Desventajas del controlador de LMK integrado en el kernel

Android da de baja el controlador de LMK debido a varios problemas, incluidos los siguientes:

  • Los dispositivos con poca RAM debían ajustarse de forma agresiva y, aun así, tenían un rendimiento bajo en cargas de trabajo con una gran caché de páginas activa respaldada por archivos. El bajo rendimiento generó una hiperpaginación y ninguna muerte.
  • El controlador de kernel de LMK se basaba en límites de memoria libre, sin escalamiento según la presión de la memoria.
  • Debido a la rigidez del diseño, los socios suelen personalizar el controlador para que funcione en sus dispositivos.
  • El controlador de LMK se conectó a la API de la contracción de los fragmentos, que no se diseñó para operaciones pesadas, como buscar objetivos y finalizarlos, lo que ralentizó el proceso de vmscan.

LMKD de espacio del usuario

El lmkd del espacio del usuario implementa la misma funcionalidad que el controlador integrado en el kernel, pero usa los mecanismos existentes del kernel para detectar y estimar la presión de la memoria. Estos mecanismos incluyen el uso de eventos vmpressure generados por el kernel o monitores de información de demora de presión (PSI) para obtener notificaciones sobre los niveles de presión de la memoria y el uso de funciones de cgroup de memoria para limitar los recursos de memoria asignados a cada proceso según su importancia.

Cómo usar el lmkd del espacio de usuario en Android 10

En Android 9 y versiones posteriores, se activa el espacio de usuario lmkd si no se detecta un controlador de LMK en el kernel. Debido a que el espacio de usuario lmkd requiere compatibilidad del kernel con los cgroups de memoria, el kernel se debe compilar con la siguiente configuración:

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

Estrategias de eliminación

El lmkd del espacio de usuario admite estrategias de eliminación basadas en eventos vmpressure o monitores de PSI, su gravedad y otros indicadores, como el uso de intercambio. Las estrategias de eliminación difieren entre los dispositivos con poca memoria y los de alto rendimiento:

  • En dispositivos con poca memoria, el sistema debe tolerar una presión de memoria más alta como modo de funcionamiento normal.
  • En los dispositivos de alto rendimiento, la presión de memoria debe considerarse una situación anormal y corregirse antes de que afecte el rendimiento general.

Puedes configurar la estrategia de cierre con la propiedad ro.config.low_ram. Para obtener más información, consulta Configuración de RAM baja.

El espacio de usuario lmkd también admite un modo heredado en el que toma decisiones de eliminación con las mismas estrategias que el controlador de LMK integrado en el kernel (es decir, los umbrales de memoria libre y caché de archivos). Para habilitar el modo heredado, establece la propiedad ro.lmk.use_minfree_levels en true.

Configura lmkd

Configura lmkd para un dispositivo específico con las siguientes propiedades.

Propiedad Usar Predeterminado
ro.config.low_ram Especifica si el dispositivo tiene poca RAM o tiene un rendimiento alto. false
ro.lmk.use_psi Usa monitores de PSI (en lugar de eventos vmpressure). true
ro.lmk.use_minfree_levels Usa umbrales de memoria libre y caché de archivos para tomar decisiones de finalización de procesos (es decir, que coincidan con la funcionalidad del controlador de LMK integrado en el kernel). false
ro.lmk.low La puntuación mínima de oom_adj para procesos que se pueden finalizar en un nivel de vmpressure bajo. 1001
(inhabilitado)
ro.lmk.medium La puntuación mínima de oom_adj para procesos aptos para su cierre en el nivel medio de vmpressure. 800
(servicios almacenados en caché o no esenciales)
ro.lmk.critical Es la puntuación mínima de oom_adj para los procesos aptos para finalizarse a nivel crítico de vmpressure. 0
(cualquier proceso)
ro.lmk.critical_upgrade Habilitar la actualización al nivel crítico false
ro.lmk.upgrade_pressure El mem_pressure máximo al que se actualiza el nivel porque el sistema intercambia demasiado. 100
(inhabilitado)
ro.lmk.downgrade_pressure Es el mem_pressure mínimo en el que se ignora un evento vmpressure porque todavía hay suficiente memoria libre disponible. 100
(inhabilitado)
ro.lmk.kill_heaviest_task Cancela la tarea apta más pesada (mejor decisión) en comparación con cualquier tarea apta (decisión rápida). false
ro.lmk.kill_timeout_ms Es la duración en milisegundos después de un cierre cuando no se realizará ningún cierre adicional. 0
(inhabilitado)
ro.lmk.debug Habilita los registros de depuración de lmkd. false

Ejemplo de configuración del dispositivo:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.lmk.low=1001 \
    ro.lmk.medium=800 \
    ro.lmk.critical=0 \
    ro.lmk.critical_upgrade=false \
    ro.lmk.upgrade_pressure=100 \
    ro.lmk.downgrade_pressure=100 \
    ro.lmk.kill_heaviest_task=true

LMKD de espacio del usuario en Android 11

Android 11 mejora lmkd con la introducción de una nueva estrategia de cierre. La estrategia de eliminación usa un mecanismo de PSI para la detección de presión de la memoria que se introdujo en Android 10. lmkd en Android 11 tiene en cuenta los niveles de uso de recursos de memoria y el intercambio para evitar la falta de memoria y la degradación del rendimiento. Esta estrategia reemplaza las estrategias anteriores y se puede usar en dispositivos de alto rendimiento y con poca RAM (Android Go).

Requisitos del kernel

En dispositivos con Android 11, lmkd requiere las siguientes funciones del kernel:

  • Incluye parches de PSI y habilita PSI (portabilidad a versiones anteriores disponible en los kernels comunes de Android 4.9, 4.14 y 4.19).
  • Se incluyen parches de compatibilidad con PIDFD (portabilidad a versiones anteriores disponibles en los kernels comunes de Android 4.9, 4.14 y 4.19).
  • Para dispositivos con poca RAM, incluye cgroups de memoria.

El kernel se debe compilar con los siguientes parámetros de configuración:

CONFIG_PSI=y

Cómo configurar lmkd en Android 11

La estrategia de cierre de memoria en Android 11 admite los controles de ajuste y los valores predeterminados que se indican a continuación. Estas funciones funcionan en dispositivos de alto rendimiento y de baja RAM.

Propiedad Usar Predeterminado
Alto rendimiento RAM baja
ro.lmk.psi_partial_stall_ms Es el umbral de detención PSI parcial, en milisegundos, para activar la notificación de memoria baja. Si el dispositivo recibe notificaciones de presión de memoria demasiado tarde, disminuye este valor para activar notificaciones más tempranas. Si las notificaciones de presión de memoria se activan innecesariamente, aumenta este valor para que el dispositivo sea menos sensible al ruido. 70 200
ro.lmk.psi_complete_stall_ms Es el umbral de detención de PSI completo, en milisegundos, para activar notificaciones de memoria críticas. Si el dispositivo recibe notificaciones de presión de memoria críticas demasiado tarde, disminuye este valor para activar notificaciones más anticipadas. Si las notificaciones de presión de memoria crítica se activan de forma innecesaria, aumenta este valor para que el dispositivo sea menos sensible al ruido. 700
ro.lmk.thrashing_limit Es la cantidad máxima de fallas de conjunto de trabajo como porcentaje del tamaño total de la caché de páginas respaldada por archivos. Los errores de reintento del conjunto de trabajo por encima de este valor significan que se considera que el sistema está sobrecargando su caché de páginas. Si el rendimiento del dispositivo se ve afectado durante la presión de la memoria, disminuye el valor para limitar el intercambio. Si el rendimiento del dispositivo se cancela innecesariamente por motivos de fragmentación, aumenta el valor para permitir más fragmentación. 100 30
ro.lmk.thrashing_limit_decay Es la descomposición del umbral de saturación expresada como un porcentaje del umbral original que se usa para bajar el umbral cuando el sistema no se recupera, incluso después de un cierre. Si el intercambio continuo produce eliminaciones innecesarias, disminuye el valor. Si la respuesta a la fragmentación continua después de un cierre es demasiado lenta, aumenta el valor. 10 50
ro.lmk.swap_util_max Es la cantidad máxima de memoria intercambiada como un porcentaje de la memoria total intercambiable. Cuando la memoria intercambiable supera este límite, significa que el sistema intercambió la mayor parte de su memoria intercambiable y sigue bajo presión. Esto puede ocurrir cuando las asignaciones no intercambiables generan una presión de memoria que no se puede aliviar con el intercambio porque la mayor parte de la memoria intercambiable ya se intercambió. El valor predeterminado es 100, lo que inhabilita esta verificación de manera efectiva. Si el rendimiento del dispositivo se ve afectado durante la presión de memoria mientras el uso de intercambio es alto y el nivel de intercambio gratuito no disminuye a ro.lmk.swap_free_low_percentage, disminuye el valor para limitar el uso de intercambio. 100 100

Los siguientes controles de ajuste antiguos también funcionan con la nueva estrategia de eliminación.

Propiedad Usar Predeterminado
Alto rendimiento RAM baja
ro.lmk.swap_free_low_percentage Es el nivel de intercambio libre como porcentaje del espacio de intercambio total. “lmkd” usa este valor como un umbral para determinar cuándo considerar al sistema como sin espacio de intercambio. Si “lmkd” se cierra mientras hay demasiado espacio en el intercambio, disminuye el porcentaje. Si las eliminaciones de "lmkd" ocurren demasiado tarde, lo que permite que ocurran operaciones de OOM, aumenta el porcentaje. 20 10
ro.lmk.debug Esto habilita los registros de depuración de "lmkd". Habilita la depuración durante la configuración. false