Демон-убийца нехватки памяти

Процесс Android Low Memory Killer Daemon ( lmkd ) отслеживает состояние памяти работающей системы Android и реагирует на высокую нагрузку на память, завершая наименее важные процессы, чтобы поддерживать производительность системы на приемлемом уровне.

О давлении памяти

Система Android, в которой параллельно запущено несколько процессов, может столкнуться с ситуациями, когда системная память исчерпана, а процессы, требующие больше памяти, испытывают заметные задержки. Давление памяти , состояние, при котором системе не хватает памяти, требует от Android освобождения памяти (для уменьшения давления) путем регулирования или завершения неважных процессов, запроса процессов на освобождение некритических кэшированных ресурсов и т. д.

Исторически Android отслеживал давление системной памяти с помощью встроенного в ядро ​​драйвера low memory killer (LMK), жесткого механизма, зависящего от жестко закодированных значений. Начиная с ядра 4.12, драйвер LMK удален из ядра upstream, а lmkd пользовательского пространства выполняет задачи мониторинга памяти и завершения процессов.

Информация о срыве давления

Android 10 и выше поддерживают новый режим lmkd , который использует мониторы kernel pressure stall information (PSI) для обнаружения давления памяти. Набор исправлений PSI в ядре upstream (перенесенный в ядра 4.9 и 4.14) измеряет количество времени, в течение которого задачи задерживаются из-за нехватки памяти. Поскольку эти задержки напрямую влияют на пользовательский опыт, они представляют собой удобную метрику для определения серьезности давления памяти. Ядро upstream также включает мониторы PSI, которые позволяют привилегированным процессам пользовательского пространства (таким как lmkd ) указывать пороговые значения для этих задержек и подписываться на события из ядра при нарушении порогового значения.

Мониторы PSI против сигналов vmpressure

Поскольку сигналы vmpressure (генерируемые ядром для обнаружения давления памяти и используемые lmkd ) часто включают в себя многочисленные ложные срабатывания, lmkd должен выполнить фильтрацию, чтобы определить, находится ли память под реальным давлением. Это приводит к ненужным пробуждениям lmkd и использованию дополнительных вычислительных ресурсов. Использование мониторов PSI приводит к более точному обнаружению давления памяти и минимизирует накладные расходы на фильтрацию.

Используйте мониторы PSI

Чтобы использовать мониторы PSI вместо событий vmpressure , настройте свойство ro.lmk.use_psi . Значение по умолчанию — true , что делает мониторы PSI механизмом обнаружения давления памяти по умолчанию для lmkd . Поскольку мониторы PSI требуют поддержки ядра, ядро ​​должно включать исправления обратного порта PSI и быть скомпилировано с включенной поддержкой PSI ( CONFIG_PSI=y ).

Недостатки встроенного в ядро ​​драйвера LMK

Android прекращает поддержку драйвера LMK из-за ряда проблем, в том числе:

  • Устройства с малым объемом ОЗУ приходилось настраивать агрессивно, и даже тогда они плохо работали на рабочих нагрузках с большим кэшем страниц с поддержкой файлов. Низкая производительность приводила к пробуксовке и отсутствию убийств.
  • Драйвер ядра LMK полагался на ограничения свободной памяти, не масштабируясь в зависимости от нагрузки на память.
  • Из-за жесткости конструкции партнеры часто настраивали драйвер так, чтобы он работал на их устройствах.
  • Драйвер LMK подключался к API скрайнера, который не был предназначен для выполнения сложных операций, таких как поиск целей и их уничтожение, что замедляло процесс vmscan .

Пользовательское пространство lmkd

Пользовательский lmkd реализует ту же функциональность, что и драйвер ядра, но использует существующие механизмы ядра для обнаружения и оценки давления памяти. Такие механизмы включают использование событий vmpressure , сгенерированных ядром, или мониторов Pressure Stall Information (PSI) для получения уведомлений об уровнях давления памяти, а также использование функций CGroup памяти для ограничения ресурсов памяти, выделяемых каждому процессу, на основе важности процесса.

Используйте lmkd пользовательского пространства в Android 10

В Android 9 и выше lmkd пользовательского пространства активируется, если драйвер LMK в ядре не обнаружен. Поскольку lmkd пользовательского пространства требует поддержки ядра для групп памяти, ядро ​​должно быть скомпилировано со следующими параметрами конфигурации:

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

Стратегии убийства

Пользовательское пространство lmkd поддерживает стратегии уничтожения на основе событий vmpressure или мониторов PSI, их серьезности и других подсказок, таких как использование подкачки. Стратегии уничтожения различаются для устройств с низким объемом памяти и высокопроизводительных устройств:

  • На устройствах с небольшим объемом памяти система должна допускать более высокую нагрузку на память в обычном режиме работы.
  • На высокопроизводительных устройствах нехватку памяти следует рассматривать как ненормальную ситуацию и устранять ее до того, как она повлияет на общую производительность.

Вы можете настроить стратегию уничтожения с помощью свойства ro.config.low_ram .

Пользовательский lmkd также поддерживает устаревший режим, в котором он принимает решения об уничтожении, используя те же стратегии, что и драйвер ядра LMK (то есть пороги свободной памяти и файлового кэша). Чтобы включить устаревший режим, установите свойство ro.lmk.use_minfree_levels в true .

Настроить lmkd

Настройте lmkd для конкретного устройства, используя следующие свойства.

Свойство Использовать По умолчанию
ro.config.low_ram Укажите, является ли устройство устройством с малым объемом оперативной памяти или высокопроизводительным. false
ro.lmk.use_psi Используйте мониторы PSI (вместо событий vmpressure ). true
ro.lmk.use_minfree_levels Использовать пороговые значения свободной памяти и файлового кэша для принятия решений о завершении процесса (то есть соответствовать функциональности встроенного в ядро ​​драйвера LMK). false
ro.lmk.low Минимальный балл oom_adj для процессов, которые могут быть завершены при низком уровне vmpressure . 1001
(неполноценный)
ro.lmk.medium Минимальный балл oom_adj для процессов, которые могут быть завершены при среднем уровне vmpressure . 800
(кэшированные или необязательные службы)
ro.lmk.critical Минимальный балл oom_adj для процессов, которые могут быть завершены при критическом уровне vmpressure . 0
(любой процесс)
ro.lmk.critical_upgrade Включить обновление до критического уровня. false
ro.lmk.upgrade_pressure Максимальное значение mem_pressure , при котором уровень повышается, поскольку система выполняет слишком большой подкачок. 100
(неполноценный)
ro.lmk.downgrade_pressure Минимальное значение mem_pressure , при котором событие vmpressure игнорируется, поскольку все еще доступно достаточно свободной памяти. 100
(неполноценный)
ro.lmk.kill_heaviest_task Уничтожить самую сложную подходящую задачу (лучшее решение) против любой подходящей задачи (быстрое решение). false
ro.lmk.kill_timeout_ms Длительность в миллисекундах после убийства, когда никаких дополнительных убийств не производится. 0
(неполноценный)
ro.lmk.debug Включить журналы отладки lmkd . false

Пример конфигурации устройства:

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 в Android 11

Android 11 улучшает lmkd , вводя новую стратегию уничтожения. Стратегия уничтожения использует механизм PSI для обнаружения давления памяти, представленный в Android 10. lmkd в Android 11 учитывает уровни использования ресурсов памяти и пробуксовку, чтобы предотвратить нехватку памяти и снижение производительности. Эта стратегия уничтожения заменяет предыдущие стратегии и может использоваться как на высокопроизводительных устройствах, так и на устройствах с низким объемом оперативной памяти (Android Go).

Требования к ядру

Для устройств Android 11 lmkd требует следующие функции ядра:

  • Включите исправления PSI и включите PSI (обратные порты доступны в общих ядрах Android 4.9, 4.14 и 4.19).
  • Включить исправления поддержки PIDFD (обратные порты доступны в общих ядрах Android 4.9, 4.14 и 4.19).
  • Для устройств с малым объемом оперативной памяти включите контрольные группы памяти.

Ядро должно быть скомпилировано со следующими параметрами конфигурации:

CONFIG_PSI=y

Настройка lmkd в Android 11

Стратегия уничтожения памяти в Android 11 поддерживает ручки настройки и значения по умолчанию, перечисленные ниже. Эти функции работают как на высокопроизводительных устройствах, так и на устройствах с низким объемом оперативной памяти.

Свойство Использовать По умолчанию
Высокая производительность Мало оперативной памяти
ro.lmk.psi_partial_stall_ms Порог частичного срыва PSI в миллисекундах для срабатывания уведомления о низком уровне памяти. Если устройство получает уведомления о давлении памяти слишком поздно, уменьшите это значение, чтобы срабатывать более ранние уведомления. Если уведомления о давлении памяти срабатывают без необходимости, увеличьте это значение, чтобы сделать устройство менее чувствительным к шуму. 70 200
ro.lmk.psi_complete_stall_ms Полный порог срыва PSI в миллисекундах для срабатывания критических уведомлений о памяти. Если устройство получает критические уведомления о давлении памяти слишком поздно, уменьшите это значение, чтобы срабатывать более ранние уведомления. Если критические уведомления о давлении памяти срабатывают без необходимости, увеличьте это значение, чтобы сделать устройство менее чувствительным к шуму. 700
ro.lmk.thrashing_limit Максимальное количество сбоев рабочего набора в процентах от общего размера кэша страниц с файловой поддержкой. Сбои рабочего набора выше этого значения означают, что система считается перегружающим свой кэш страниц. Если производительность устройства снижается из-за нехватки памяти, уменьшите значение, чтобы ограничить перегрузку. Если производительность устройства без необходимости останавливается из-за перегрузки, увеличьте значение, чтобы разрешить большую перегрузку. 100 30
ro.lmk.thrashing_limit_decay Снижение порога трешинга, выраженное в процентах от исходного порога, используется для снижения порога, когда система не восстанавливается, даже после уничтожения. Если непрерывное трешинг приводит к ненужным уничтожениям, уменьшите значение. Если реакция на непрерывное трешинг после уничтожения слишком медленная, увеличьте значение. 10 50
ro.lmk.swap_util_max Максимальный объем подкачиваемой памяти в процентах от общего объема подкачиваемой памяти. Когда подкачиваемая память превышает этот предел, это означает, что система подкачала большую часть своей подкачиваемой памяти и все еще находится под давлением. Это может произойти, когда не подкачиваемые выделения создают давление памяти, которое не может быть снято подкачкой, поскольку большая часть подкачиваемой памяти уже подкачана. Значение по умолчанию — 100, что фактически отключает эту проверку. Если производительность устройства страдает при давлении памяти, когда использование подкачки высокое, а уровень свободного подкачки не падает до ro.lmk.swap_free_low_percentage , уменьшите значение, чтобы ограничить использование подкачки. 100 100

Следующие старые ручки настройки также работают с новой стратегией убийства.

Свойство Использовать По умолчанию
Высокая производительность Мало оперативной памяти
ro.lmk.swap_free_low_percentage Уровень свободного пространства подкачки в процентах от общего пространства подкачки. `lmkd` использует это значение в качестве порогового значения, когда следует считать систему испытывающей нехватку пространства подкачки. Если `lmkd` убивает, когда в подкачке слишком много места, уменьшите процент. Если уничтожения `lmkd` происходят слишком поздно, позволяя происходить уничтожениям OOM, увеличьте процент. 20 10
ro.lmk.debug Это включает журналы отладки `lmkd`. Включить отладку во время настройки. false