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

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

Использование пользовательского пространства 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