Демон LMK (lmkd) отслеживает состояние памяти в работающей системе Android и при ее нехватке завершает наименее важные процессы, чтобы поддерживать производительность системы на приемлемом уровне.
О нагрузке на память
Если система Android одновременно выполняет несколько процессов, может возникнуть ситуация, когда системная память будет исчерпана и процессы, требующие больше памяти, будут выполняться с заметными задержками. Нехватка памяти – это состояние, в котором системе не хватает памяти. Чтобы устранить эту проблему, Android освобождает память, ограничивая или завершая работу второстепенных процессов, запрашивая у процессов освобождение некритичных кешированных ресурсов и т. д.
Раньше Android отслеживал нехватку системной памяти с помощью встроенного в ядро драйвера LMK (low memory killer) – жесткого механизма, который зависит от значений, заданных в коде. Начиная с версии ядра 4.12 драйвер LMK удален из вышестоящего ядра, а задачи по мониторингу памяти и завершению процессов выполняет пользовательское пространство lmkd.
Информация о задержках из-за нагрузки
В Android 10 и более поздних версиях поддерживается новый режим lmkd, в котором для обнаружения нехватки памяти используются мониторы PSI (Pressure Stall Information) ядра. Набор исправлений 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 в ядре
Драйвер LMK в Android устарел по ряду причин, в том числе:
- Устройства с небольшим объемом ОЗУ приходилось настраивать очень тщательно, но даже в этом случае они плохо справлялись с задачами, требующими большого объема активного кеша страниц с поддержкой файлов. Из-за низкой производительности произошел сбой и не было убийств.
- Драйвер ядра LMK полагался на ограничения свободной памяти без масштабирования на основе нагрузки на память.
- Из-за жесткости дизайна партнеры часто настраивали драйвер, чтобы он работал на их устройствах.
- Драйвер LMK был подключен к API slab shrinker, который не был предназначен для тяжелых операций, таких как поиск целей и их уничтожение, что замедляло процесс
vmscan.
Пользовательский lmkd
Пространство пользователя lmkd реализует те же функции, что и драйвер в ядре, но использует существующие механизмы ядра для обнаружения и оценки нехватки памяти. К таким механизмам относятся события vmpressure, сгенерированные ядром, или мониторы 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 |
Максимальное количество повторных ошибок рабочего набора в процентах от общего размера кеша страниц, связанных с файлами. Если значение параметра workingset refaults превышает указанное, это означает, что система активно использует кеш страниц. Если при нехватке памяти производительность устройства снижается, уменьшите значение, чтобы ограничить перегрузку. Если производительность устройства снижается без необходимости из-за перегрузки, увеличьте значение, чтобы допустить большую перегрузку. | 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 |
Уровень свободного swap-пространства в процентах от общего объема. `lmkd` использует это значение в качестве порога, при котором система считается испытывающей нехватку места в файле подкачки. Если `lmkd` завершает процессы, когда в разделе подкачки слишком много свободного места, уменьшите процент. Если `lmkd` завершает процессы слишком поздно, из-за чего происходят завершения OOM, увеличьте процент. | 20 |
10 |
ro.lmk.debug |
Это позволит включить журналы отладки `lmkd`. Включите отладку во время настройки. | false |
|