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

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

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

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

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

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

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

Сравнение показаний мониторов PSI и сигналов давления vm

Поскольку сигналы 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 или мониторов информации о задержках (PSI) для получения уведомлений об уровнях нехватки памяти, а также использование функций cgroup памяти для ограничения ресурсов памяти, выделяемых каждому процессу, в зависимости от важности процесса.

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

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

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. В Android 11 механизм lmkd учитывает уровни использования ресурсов памяти и рывки, чтобы предотвратить голодание памяти и снижение производительности. Эта стратегия завершения процессов заменяет предыдущие стратегии и может использоваться как на высокопроизводительных устройствах, так и на устройствах с малым объемом оперативной памяти (Android Go).

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

Для устройств на Android 11 lmkd требует наличия следующих компонентов ядра:

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

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

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