На этой странице рассматривается взаимодействие между kswapd и lmkd на Android, демонстрируется, как они работают вместе для управления нехваткой памяти.
Фон
Android использует два основных механизма для высвобождения памяти, когда в системе её недостаточно:
-
kswapd: Стандартный демон ядра Linux, который освобождает страницы, вытесняя чистые страницы, хранящиеся в файлах, или заменяя анонимные страницы на ZRAM. -
lmkd: Демон завершения процессов в пользовательском пространстве Android, отвечающий за экономию памяти. Когдаkswapdне справляется с потребностями в памяти и системная нагрузка возрастает (о чем сигнализирует PSI),lmkdвмешивается, чтобы завершить процессы и освободить большие объемы памяти.
kswapd и lmkd — это две взаимодополняющие системы высвобождения памяти. Они работают для достижения одной и той же цели (создание свободной памяти), но разными способами. Для сравнения:
- Восстанавливаемое и деструктивное удаление :
kswapdудаляет страницы памяти, которые можно прочитать из хранилища, или выгружает страницы памяти в другие разделы памяти или хранилище, которые можно прочитать по запросу.lmkdзавершает процессы, что уничтожает энергонезависимое состояние. - Освобождение полосы пропускания :
kswapdтратит больше ресурсов ЦП на освобождение заданного объема свободной памяти, чемlmkd, и на это уходит больше времени.lmkdможет освобождать большие объемы памяти короткими импульсами с относительно небольшими усилиями. Следует учитывать, что на мобильных устройствах затраты ресурсов ЦП приводят не только к задержке, но и к расходу заряда батареи.
Корзины оценок OOM
Android присваивает процессам корректировку оценки нехватки памяти (Out-Of-Memory, OOM) ( oom_score_adj ) в зависимости от их важности для пользователя. Процессы с более высокими оценками завершаются первыми.
К распространённым категориям относятся:
- Кэшированные процессы (оценка >= 900): процессы, которые в данный момент не требуются, сохранены для более быстрого перезапуска.
- Сервис (оценка 500): Процессы, размещающие запущенные сервисы.
- Служба переднего плана (оценка 200): Процессы, в которых размещены службы переднего плана.
- Активный режим (оценка 0): приложение, с которым пользователь взаимодействует в данный момент.
Подробный анализ: срабатывание PSI и LMKD.
Что такое PSI?
Функция Pressure Stall Information (PSI) — это функция ядра Linux, которая предоставляет стандартный способ измерения нехватки ресурсов. Она отслеживает время задержки выполнения задач из-за нехватки ресурсов ЦП, памяти и ввода-вывода.
Память PSI: "частично" против "полностью"
Memory PSI отслеживает задержки, вызванные нехваткой памяти (например, ожиданием освобождения страниц или ошибками). Он предоставляет две метрики:
-
some: Процент времени, в течение которого хотя бы одна задача была приостановлена из-за нехватки памяти. Это указывает на то, что нехватка памяти влияет на производительность, но некоторая работа все же продолжается. -
full: Процент времени, в течение которого все не простаивающие задачи были одновременно приостановлены. Это указывает на критическое состояние, при котором система полностью заблокирована в ожидании доступа к памяти.
Как PSI запускает LMKD
Демон lmkd в пользовательском пространстве регистрируется в ядре для получения уведомлений о превышении пороговых значений PSI (путем мониторинга /proc/pressure/memory ). Когда система испытывает высокую нагрузку на память (например, full задержка, превышающая заданную продолжительность), ядро пробуждает lmkd . Затем lmkd оценивает состояние системы и решает, следует ли завершать процессы и какие именно, основываясь на их показателях нехватки памяти (OOM) и размере.
тюнинг LMKD
Поведение LMKD можно настроить с помощью системных свойств.
Определение параметров настройки устройства
Текущие значения параметров настройки LMKD на подключенном устройстве можно узнать, выполнив следующую команду:
adb shell getprop | grep lmk
Общие свойства LMKD
Вот некоторые из ключевых параметров, используемых для настройки LMKD (полный список см. в документации Android ):
-
ro.lmk.use_psi: Установите значениеtrue, чтобы использовать мониторы PSI для определения давления в памяти (по умолчанию в Android 10+). -
ro.lmk.psi_partial_stall_ms:someзначение длительности (частичной) задержки в миллисекундах, при котором срабатывает команда kill (по умолчанию 70 мс на обычных устройствах, 200 мс на устройствах с малым объемом оперативной памяти). -
ro.lmk.psi_complete_stall_ms: Пороговое значение длительностиfullзадержки в миллисекундах для запуска аварийного завершения работы (по умолчанию 700 мс). -
ro.lmk.kill_heaviest_task: Еслиtrue, LMKD завершает процесс, использующий больше всего памяти среди кандидатов в одном и том же сегменте OOM.
Соответствующие параметры настройки на тестовом устройстве (Google Pixel 8 Pro)
(Примечание: Типичные настройки по умолчанию для высокопроизводительных устройств под управлением Android 15)
-
ro.lmk.use_psi:true -
ro.lmk.psi_partial_stall_ms:70(типичное значение) -
ro.lmk.psi_complete_stall_ms:700(типичное значение) -
ro.lmk.kill_heaviest_task:true
Проверка ZRAM и свопа
Объем ZRAM сильно влияет на скорость заполнения файла подкачки и запуска процессов LMKD. Проверить состояние ZRAM и файла подкачки на устройстве можно с помощью следующих команд:
# Check ZRAM sizing and usage
adb shell free -m
# Check swap partition details
adb shell cat /proc/swaps
Практическое упражнение: запуск kswapd и lmkd
В этом упражнении вы будете использовать пример приложения KswapdLmkdLab для создания процессов в разных областях нехватки памяти (OOM), а затем будете использовать память в основном процессе для запуска kswapd и lmkd .
Приложение настроено на автоматическое создание дочерних процессов и выделение памяти, чтобы сделать их привлекательными целями для LMKD.
1. Создание подпроцессов
При запуске приложение автоматически запускает следующие дочерние процессы:
- Кэшированный процесс (oom_score_adj >= 900)
- Процесс обслуживания (oom_score_adj 500)
- Процесс переднего плана (oom_score_adj 200)
Проверьте процессы и их показатели нехватки памяти (OOM) с помощью ADB:
adb shell dumpsys activity processes | grep com.android.kswapdlmkdlab
Пример выходных данных:
Proc # 0: fg T/A/TOP LCMNFUATI t: 0 18959:com.android.kswapdlmkdlab/u0a358 (top-activity)
Proc # 1: prcp b/ /FGS -------TI t: 0 19050:com.android.kswapdlmkdlab:foreground/u0a358 (fg-service)
Proc # 2: svc b/ /SVC -------TI t: 0 19077:com.android.kswapdlmkdlab:service/u0a358 (started-services)
Proc # 3: cch b/ /CACC -------TI t: 0 19014:com.android.kswapdlmkdlab:cached/u0a358 (cch-client-act)
Сокращения состояний процесса соответствуют:
-
fg: Передний план (оценка нехватки памяти 0) -
prcp: Ощутимый (Фоновая служба, оценка нехватки памяти 200) -
svc: Служба запущена (оценка нехватки памяти 500) -
cch: Кэшированный процесс (оценка нехватки памяти 900)
2. Вызвать давление памяти.
Приложение автоматически начнет выделение памяти в основном процессе. Для повышения эффективности теста на устройствах с большим объемом оперативной памяти приложение также дает команду дочерним процессам выделить память (например, по 500 МБ каждый), чтобы сделать их более подходящими целями для LMKD.
Пример работы приложения
Вот скриншот приложения после тестового запуска на Google Pixel 8 Pro (с примерно 12 ГБ оперативной памяти).

Перфетто-анализ следов
Для фиксации взаимодействия используйте следующую конфигурацию Perfetto, чтобы зафиксировать планирование, счетчики памяти, срабатывания LMK и информацию о задержке из-за перегрузки (PSI).
Идеальная конфигурация
Для фиксации взаимодействия запустите Perfetto с учетом планирования, счетчиков памяти, прерываний LMK и информации о задержке из-за перегрузки (PSI):
adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/kswapd_lmkd.perfetto-trace <<EOF
buffers: { size_kb: 131072 }
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "lowmemorykiller/lowmemory_kill"
ftrace_events: "vmscan/mm_vmscan_kswapd_wake"
ftrace_events: "vmscan/mm_vmscan_kswapd_sleep"
ftrace_events: "psi/psi_event"
}
}
}
duration_ms: 180000
EOF
Просмотрите трассировку
Ниже приведён скриншот трассировки, показывающий период времени незадолго до завершения процесса :cached (наиболее легко завершаемый процесс) и до завершения процесса :foreground (наименее легко завершаемый процесс).

Как видите, MemFree уже довольно низкий и постоянно находится под давлением. kswapd постоянно работает и снижает нагрузку, удаляя страницы mem.rss.file и перемещая mem.rss.anon в mem.swap из всех процессов kswapdlmkdlab (основного процесса и его дочерних процессов), а также, вероятно, из других процессов, не показанных на этом скриншоте. В то же время приложение kswapdlmkdlab продолжает выделять память, увеличивая нагрузку быстрее, чем kswapd может её освободить.
Когда давление становится слишком высоким, как это видно по высокому значению psi.mem в течение достаточно длительного периода времени, lmkd активируется и завершает некоторые процессы. Вы можете видеть, что lmkd учитывает показатели нехватки памяти (OOM), сначала завершая kswapdlmkdlab:cached , затем :service , а затем :foreground .
Проанализируйте хронологию событий и поразмышляйте над следующим:
- Как
kswapdиlmkdдополняют друг друга:kswapdпервым реагирует на нехватку памяти, ноlmkdпомогает, когда пропускная способностьkswapdпо освобождению памяти не соответствует потребностям в выделении ресурсов. - Скорость освобождения памяти: обратите внимание на время работы процессора, затраченное на
kswapd, и на объем памяти, освобождаемый путем удаленияmem.rss.fileили заменыmem.rss.anonнаmem.swap. Сравните это с кратковременными всплесками активности вlmkd, которые приводят к освобождению больших объемов частной памяти процесса.
Запросы
Выполните эти запросы в пользовательском интерфейсе Perfetto (SQL-запрос), чтобы извлечь данные из трассировки.
1. Активность kswapd
Чтобы узнать, когда демон подкачки ядра был активен и запущен, выполните следующую команду:
SELECT ts, dur, state
FROM thread_state
JOIN thread USING (utid)
WHERE thread.name LIKE 'kswapd%'
AND state = 'Running'
LIMIT 5;
Пример выходных данных:
| тс | дур | состояние |
|---|---|---|
| 30317633052969 | 159180 | Бег |
| 30317633398347 | 3999186 | Бег |
| 30317638448111 | 1847941 | Бег |
| 30317641455354 | 1031006 | Бег |
| 30317643272615 | 888387 | Бег |
2. LMKD убивает
LMKD записывает сообщения о завершении операций при нехватке памяти в таблицу instant . Чтобы запросить все сообщения о завершении операций LMKD:
SELECT ts, name
FROM instant
WHERE name LIKE 'lmk,%'
ORDER BY ts ASC;
Формат названия события: lmk,<pid>,<kill_reason>,<oom_score_adj>,<min_oom_score>,<max_thrashing> .
-
kill_reason: Целое число, указывающее причину, по которойlmkdрешил завершить процесс (определено вsystem/memory/lmkd/statslog.h):-
0:PRESSURE_AFTER_KILL -
1:NOT_RESPONDING -
2:LOW_SWAP_AND_THRASHINGРАЗМЕЩЕНИЯ МАГАЗИНА И ПРОБЛЕМЫ С ИЗМЕНЕНИЕМ ОБЪЕМА ДАННЫХ (Объем файла подкачки ZRAM крайне мал, и произошли проблемы с изменением объема данных) -
3:LOW_MEM_AND_SWAP(Система испытывает нехватку как свободной памяти, так и подкачки ZRAM) -
4:LOW_MEM_AND_THRASHING -
5:DIRECT_RECL_AND_THRASHING -
6:LOW_MEM_AND_SWAP_UTIL -
7:LOW_FILECACHE_AFTER_THRASHING -
8:LOW_MEM -
9:DIRECT_RECL_STUCK
-
-
max_thrashing: Максимальный процент перегрузки страницы в момент завершения процесса.
Пример выходных данных:
| тс | имя |
|---|---|
| 30326148679967 | lmk,2308,3,900,201,0 |
| 30330439763710 | lmk,2309,3,500,201,0 |
| 30334985999837 | lmk,2310,2,200,0,307 |
Визуализация
Для визуализации данных можно использовать следующий скрипт gnuplot для построения графика свободной памяти системы, активности kswapd, количества завершенных процессов lmkd и PSI в виде единого временного ряда. Скрипт предполагает, что он запускается из корневого каталога сборки Android.
Пример выходного графика
Следующий график был построен с использованием приведенного выше скрипта на основе выборочных данных, репрезентативных для тестового запуска.

Пояснение к сюжету:
Этот график иллюстрирует динамическое взаимодействие между различными компонентами управления памятью во время стресс-теста:
- Снижение объема свободной памяти : по мере того, как основное приложение выделяет память, объем свободной системной памяти (фиолетовая линия) неуклонно уменьшается.
- Активация kswapd : Когда уровень свободной памяти падает ниже определённых значений,
kswapdактивируется (синие импульсы), чтобы освободить память, используя ZRAM в качестве буфера. Это проявляется в виде периодических всплесков. - Скачки PSI : Поскольку
kswapdс трудом справляется с высокой скоростью выделения памяти, потоки начинают зависать при выделении памяти, что приводит к скачкам PSI (информация о задержке из-за давления) (зеленая линия). - LMKD завершает процессы : Когда PSI достигает критического уровня (например, превышает пороговое значение
ro.lmk.psi_complete_stall_ms) и объем свободной памяти крайне низок,lmkdвмешивается, завершая процессы с низким приоритетом (оранжевые импульсы в моменты времени 30 и 45), чтобы освободить большие объемы памяти. Обратите внимание, что сразу после завершения процесса объем свободной памяти увеличивается, а PSI падает, демонстрируя эффективность завершения процесса в снижении нагрузки. ________________________________________________________________________________
← Освобождение памяти: вытеснение и замена | ↑ Вверх