демон управления памятью

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

Фон

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

Архитектура и управление ZRAM

После завершения загрузки (то есть, когда sys.boot_completed=1 ) mmd_setup пытается настроить ZRAM с заданными параметрами. После завершения настройки ZRAM система активирует службу mmd , которая обрабатывает текущие задачи обслуживания.

В проекте mmd операции обслуживания инициируются с system_server путем отправки запросов Binder к mmd через интерфейс IMmd . mmd обрабатывает задачи обслуживания, такие как обратная запись ZRAM, пересжатие и обратная запись для каждого процесса, на основе собственного внутреннего механизма политик. Как планирование из ActivityManagerService , так и политики обслуживания ZRAM могут быть настроены с помощью системных свойств.

Интеграция системного сервера (system_server)

Процесс system_server на основе Java определяет, когда запускается mmd . Этот процесс разделяет глобальные проверки и целевые оптимизации памяти для каждого приложения.

Стандартное техническое обслуживание после обработки

Глобальное обслуживание ZRAM осуществляется службой ActivityManagerService с использованием com.android.server.memory.ZramMaintenance .

zram-maintenance

Рисунок 1. Схема планирования технического обслуживания ZRAM.

  • Механизм планирования: ZramMaintenance регистрирует периодическое фоновое задание в JobScheduler Android.
  • Ограничения задания: Чтобы предотвратить зависания пользовательского интерфейса в фоновом режиме или конкуренцию за ресурсы ЦП, задание явно настраивается с помощью setRequiresDeviceIdle(true) и setRequiresBatteryNotLow(true) .
  • Запуск Binder: Когда планировщик запускает onStartJob() , system_server вызывает mmd.doZramMaintenanceAsync() . Это односторонний асинхронный вызов Binder; system_server не блокируется, ожидая завершения циклов обслуживания. mmd ставит этот вызов в очередь фонового рабочего потока для последовательного выполнения пересжатия и записи.

Обратная запись для каждого процесса

Целенаправленное освобождение памяти для каждого процесса управляется службой ActivityManagerService с помощью com.android.server.am.CachedAppOptimizer .

mmd-writeback

Рисунок 2. Схема обратной записи mmd для каждого процесса.

Когда процесс переходит в фоновое кэшированное состояние, ActivityManager выполняет уплотнение памяти. Если пользователю будет виден процесс с низким потреблением памяти, то есть процесс содержит Activity, и если запись ZRAM для каждого процесса сведет объем используемой памяти к нулю, то система выполняет следующие шаги:

  1. После завершения сжатия данных CachedAppOptimizer отправляет отложенное сообщение ( ZRAM_WRITEBACK_MSG ) своему внутреннему обработчику сжатия (с задержкой mZramWritebackWaitSeconds ).
  2. По истечении задержки ActivityManager открывает защищенный дескриптор файла процесса pidfd .
  3. Сервер системы вызывает mmd.asyncWritebackProcessZramMemory(pfd, callback) .
  4. mmd выполняет ioctl-запрос на обратную запись для каждого процесса и сообщает об этом с помощью IMmdProcessWritebackCallback . В случае успеха ActivityManager помечает запись процесса ( setIsZramWrittenBack(app, true) ) для повышения oom_score_adj процесса и записывает метрики в FrameworkStatsLog.ZRAM_WRITEBACK_EVENT .

Предварительная выборка для каждого процесса

Когда пользователь перезапускает ранее кэшированное приложение (размороженное благодаря UNFREEZE_REASON_ACTIVITY ), ActivityManager минимизирует задержку запуска приложения, вызванную серьезными ошибками доступа к страницам в хранилище:

  1. CachedAppOptimizer перехватывает событие разморозки и вызывает prefetchZram(app) .
  2. Системный сервер распределяет pidfd приложения между Binder с помощью mmd.asyncPrefetchProcessZramMemory(pfd) . mmd выдает ioctl-запрос ZRAM_ANDROID_IOC_PROCESS_PREFETCH , указывая ядру асинхронно предварительно загрузить страницы, выгруженные из подкачки, обратно в оперативную память, пока основной поток пользовательского интерфейса приложения инициализируется.

Обзор задач по техническому обслуживанию и постобработке.

В этом разделе описываются фоновые операции обслуживания и задачи постобработки, которые выполняет mmd для оптимизации пространства подкачки и системной памяти.

Техническое обслуживание в mmd

В mmd под обслуживанием подразумеваются запланированные фоновые проверки, оптимизирующие использование пространства подкачки и физической памяти без влияния на производительность активного пользовательского интерфейса. Вместо выполнения непрерывных синхронных проверок (которые вызвали бы серьезные пробуждения ЦП и рывки пользовательского интерфейса), обслуживание осуществляется асинхронно:

  1. system_server периодически запускает doZramMaintenanceAsync() для всех компонентов Binder.

  2. mmd помещает запрос в фоновую очередь задач LowPrioWorkItem::ZramMaintenance .

  3. В mmd используется один рабочий поток, который управляет как очередью с высоким приоритетом, так и очередью с низким приоритетом. Задачи с высоким приоритетом (например, предварительная выборка для каждого процесса) обрабатываются первыми и могут вытеснять задачи с низким приоритетом. Обслуживание и обратная запись для каждого процесса обрабатываются как задачи с низким приоритетом. После извлечения из памяти рабочий поток последовательно выполняет две основные операции обслуживания:

    • ZRAM-пересжатие: выполняет пересжатие существующих страниц подкачки и повторно сжимает неиспользуемые страницы, используя алгоритм вторичного сжатия с более высоким коэффициентом сжатия, например, zstd .

    • ZRAM writeback: Сканирует неиспользуемые страницы и полностью вытесняет их из ОЗУ в резервное флэш-хранилище, используя циклическое устройство из файла в /data .

Задачи постобработки в ZRAM

В модуле ZRAM ядра Linux и архитектуре mmd задачи постобработки представляют собой асинхронные преобразования, применяемые к страницам памяти после того, как они уже были выгружены стандартными путями освобождения памяти ядра (kswapd или compaction).

Когда страница изначально выгружается в память, система отдает приоритет скорости: она использует быстрый основной алгоритм сжатия (например, lz4 ) и сохраняет сжатую страницу в оперативной памяти. Однако со временем многие выгруженные страницы становятся «холодными» или неактивными, например, фоновые приложения, кэшированные в фоновом режиме, которые не запускаются в течение нескольких часов. Оставлять «холодные» страницы в быстрой, слабо сжатой ZRAM неэффективно.

Конвейер постобработки

mmd реализует многоэтапный цикл постобработки для оптимизации этих страниц:

mmd-page-lifecycle

Рисунок 3. Жизненный цикл страницы mmd .

  1. Этап 1: Первоначальная выгрузка (быстрое сжатие): Сначала память освобождается с помощью kswapd или механизма сжатия приложения. Как правило, эта первая выгрузка выполняется с использованием алгоритма быстрого сжатия, такого как lz4 , а содержимое сохраняется в оперативной памяти.

  2. Этап 2: Маркировка простоя (старение и отслеживание): отслеживание простоя mmd использует отслеживание памяти ядра ( CONFIG_ZRAM_TRACK_ENTRY_ACTIME ) или программный маркер простоя для отслеживания того, как долго страницы оставались нетронутыми.

  3. Этап 3: Постобработка 1 - пересжатие (освобождение памяти) : Страницы, достигшие возраста простоя для пересжатия ( min_idle_seconds до max_idle_seconds ), подвергаются пересжатию. mmd записывает данные в /sys/block/zram0/recompress чтобы дать указание ядру распаковать страницу lz4 и пересжать её с помощью zstd . Это освобождает физическую оперативную память без износа флэш-памяти при записи.

  4. Этап 4: Постобработка 2 — обратная запись (вытеснение во флэш-память): Если нехватка памяти сохраняется и страницы достигают возраста простоя с обратной записью (обычно 20 часов или более), mmd запускает обратную запись. mmd записывает данные в /sys/block/zram0/idle и /sys/block/zram0/writeback чтобы полностью вытеснить сжатую страницу из ОЗУ во флэш-память.

Настройка конфигурации ZRAM

mmd загружает и обрабатывает следующие параметры настройки ZRAM:

Свойство Использовать По умолчанию
mmd.zram.enabled Включена ли настройка mmd ZRAM. false
mmd.zram.num_devices Количество устройств ZRAM для настройки. Для числа N устройства zram0 до zram<N-1> должны присутствовать до того, как система установит sys.boot_completed=1 . Свойства в списке устройств ZRAM можно настраивать для каждого устройства отдельно. 1
mmd.zram.device_priority Приоритетные значения, передаваемые при вызове функции swapon . Не задано
mmd.zram.comp_algorithm Алгоритм сжатия ZRAM. Если не указан, используется алгоритм сжатия по умолчанию ядра. Не задано
mmd.zram.size Размер ZRAM-устройства в байтах или в процентах от размера оперативной памяти устройства, например, 75% . 50%
mmd.zram.writeback.enabled Включать ли обратную запись в ZRAM. false
mmd.zram.writeback.device_size Размер устройства обратной записи в байтах или в процентах от раздела данных. Фактический размер устройства может быть скорректирован в зависимости от доступного пространства в разделе данных. 1073741824 (1 ГиБ)
mmd.zram.writeback.min_free_space_mib Минимальный объем свободного места в МиБ, который должен быть доступен после настройки устройства обратной записи. 1536 (1,5 ГиБ)
mmd.zram.writeback.use_nr_tags_prop Если true , то для настройки глубины очереди используется значение из mmd.zram.writeback.nr_tags , поддерживающее запись в ZRAM через петлевое устройство. Это обходное решение для ситуаций, когда политика SELinux поставщика не может быть настроена таким образом, чтобы разрешить mmd напрямую считывать nr_tags блочного устройства, поддерживающего /data . false
mmd.zram.writeback.nr_tags См. mmd.zram.writeback.use_nr_tags_prop . Не задано
mmd.zram.recompression.enabled Включить ли функцию пересжатия ZRAM. false
mmd.zram.recompression.algorithm Вторичный алгоритм рекомпрессии ZRAM. zstd

Свойства устройства на уровне ZRAM

Если значение mmd.zram.num_devices больше единицы, можно дополнительно настроить определенные свойства для каждого устройства ZRAM, задав для этого свойства значение, разделенное запятыми и содержащее ровно mmd.zram.num_devices элементов. К таким свойствам относятся:

  • mmd.zram.size
  • mmd.zram.comp_algorithm
  • mmd.zram.device_priority
  • mmd.zram.recompression.enabled
  • mmd.zram.recompression.huge_idle.enabled
  • mmd.zram.recompression.idle.enabled
  • mmd.zram.recompression.huge.enabled
  • mmd.zram.recompression.threshold_bytes
  • mmd.zram.recompression.algorithm
  • mmd.zram.writeback.device_size
  • mmd.zram.writeback.huge_idle.enabled
  • mmd.zram.writeback.idle.enabled
  • mmd.zram.writeback.huge.enabled

Устаревшая настройка существующей системы ZRAM

Хотя в Android по-прежнему доступна swapon_all для настройки ZRAM и дискового пространства подкачки, mmd является предпочтительным подходом к управлению ZRAM из-за упрощения настройки и расширенных функций, таких как пересжатие ZRAM.

Когда настройка ZRAM mmd включена параметром mmd.zram.enabled :

  • Настройка ZRAM в реализации swapon_all становится пустой операцией.
  • Существующие параметры конфигурации ZRAM, такие как config_zramWriteback в файле config.xml наложения и системные свойства обратной записи ro.zram.* игнорируются.

Настраиваемые параметры обслуживания ZRAM

Функция обслуживания ZRAM должна работать сразу после установки, а дополнительные настройки можно выполнить с помощью системных свойств в этом разделе.

Планирование технического обслуживания ZRAM

Эти свойства определяют, как и когда задачи обслуживания ZRAM планируются system_server сервером.

Свойство Использовать По умолчанию
mm.zram.maintenance.first_delay_seconds Задержка перед началом первого технического обслуживания ZRAM. 3600 (1 час)
mm.zram.maintenance.periodic_delay_seconds Задержка между последующими плановыми работами по техническому обслуживанию ZRAM. 3600 (1 час)
mm.zram.maintenance.require_device_idle Следует ли запускать обслуживание ZRAM только тогда, когда устройство находится в режиме ожидания. true
mm.zram.maintenance.require_battery_not_low Необходимо ли обеспечить наличие достаточного заряда батареи перед началом технического обслуживания ZRAM. true

Политика обратной записи ZRAM

Следующие параметры определяют, когда и какой тип данных записывается в резервное устройство:

Свойство Использовать По умолчанию
mmd.zram.writeback.backoff_seconds Время задержки с момента последней операции обратной записи. 600 (10 минут)
mmd.zram.writeback.min_idle_seconds В сочетании с mmd.zram.writeback.max_idle_seconds рассчитывается время простоя страницы, необходимое для обратной записи, на основе доли использования памяти. Рассчитанное время простоя экспоненциально интерполируется между двумя параметрами для минимизации работы в периоды, когда нет нехватки памяти. 72000 (20 часов)
mmd.zram.writeback.max_idle_seconds Максимальное количество секунд, используемое для динамического расчета возраста неактивной страницы на основе использования памяти. 90000 (25 часов)
mmd.zram.writeback.huge.enabled Включить ли обратную запись HUGE страниц. false
mmd.zram.writeback.idle.enabled Включить ли обратную запись в режиме IDLE ? true
mmd.zram.writeback.huge_idle.enabled Включить ли обратную запись страницы HUGE_IDLE . true
mmd.zram.writeback.min_bytes Минимальное количество байтов для обратной записи за один цикл записи в режиме ожидания. 5242880 (5 МиБ)
mmd.zram.writeback.max_bytes Максимальное количество байтов, которое можно записать обратно за один раунд записи в режиме ожидания. 314572800 (300 МиБ)
mmd.zram.writeback.max_bytes_per_day Максимальное количество байтов, которое можно записать обратно за 24 часа. 25769803776 (24 ГиБ)
mmd.zram.writeback.limit.enabled Следует ли включить учет лимитов бюджета с ежедневным списанием средств. true

политика рекомпрессии ZRAM

Следующие параметры определяют, когда и какой тип памяти будет пересжат:

Свойство Использовать По умолчанию
mmd.zram.recompression.backoff_seconds Время отката с момента последнего сжатия. 1800 (30 минут)
mmd.zram.recompression.min_idle_seconds В сочетании с mmd.zram.recompression.max_idle_seconds рассчитывается время простоя страницы, необходимое для повторного сжатия, на основе доли использования памяти. Рассчитанное время простоя экспоненциально интерполируется между двумя параметрами для минимизации работы в периоды, когда нет нагрузки на память. 7200 (2 часа)
mmd.zram.recompression.max_idle_seconds Максимальное количество секунд, используемое для динамического расчета возраста неактивной страницы. 14400 (4 часа)
mmd.zram.recompression.threshold_bytes Минимальный размер страниц ZRAM в байтах, рассматриваемых для повторного сжатия. 1024 (1 КиБ)
mmd.zram.recompression.huge.enabled Включать ли пересжатие HUGE страниц? true
mmd.zram.recompression.idle.enabled Включать ли пересжатие страниц IDLE ? true
mmd.zram.recompression.huge_idle.enabled Включать ли пересжатие страниц HUGE_IDLE . true

Отслеживание неактивных страниц ZRAM

Функция mmd ZRAM помечает страницы ZRAM как неактивные в зависимости от того, сколько времени прошло с момента последнего обращения к ним. Для работы этой функции необходимо включить параметры ядра CONFIG_ZRAM_TRACK_ENTRY_ACTIME или CONFIG_ZRAM_MEMORY_TRACKING . CONFIG_ZRAM_TRACK_ENTRY_ACTIME включен по умолчанию в ядрах GKI версии 6.18 и выше. В более ранних версиях ядра он создает накладные расходы на память и не включен по умолчанию.

Если конфигурация ядра не включена, обслуживание ZRAM mmd переключается на программную логику для отслеживания простаивающих страниц ZRAM:

  1. При запуске mmd отметьте все страницы ZRAM как неактивные.

  2. Следующие плановые работы по техническому обслуживанию ZRAM следует пропустить до истечения необходимого периода ожидания.

  3. Отложенная запись ZRAM или повторное сжатие неактивных страниц. Если из-за ограничений на отложенную запись остаются неактивные страницы, mmd продолжит запись страниц при следующем обслуживании, не помечая новые страницы как неактивные (пропуская шаг 4).

  4. Если все неактивные страницы записаны обратно, снова пометьте все страницы ZRAM как неактивные и вернитесь к шагу 2. Если обратная запись ZRAM отключена, mmd помечает все страницы ZRAM как неактивные, когда после истечения времени неактивности, необходимого для пересжатия, происходит пересжатие ZRAM.

Рекомендации по устранению неполадок и проверке

Для проверки и диагностики работы mmd и ZRAM используйте следующие этапы проверки и процедуры устранения неполадок.

Проверьте настройки ZRAM.

Чтобы убедиться, что mmd успешно настроил ZRAM во время загрузки:

  1. Проверьте активный алгоритм сжатия и размер диска:

    cat /sys/block/zram0/comp_algorithm
    cat /sys/block/zram0/disksize
    
  2. Проверьте системные свойства mmd и состояние запущенной службы:

    getprop | grep mmd.zram
    dumpsys -l | grep mmd
    

Проверка обслуживания и обратной записи ZRAM.

Убедитесь, что задачи по поддержанию записи и пересжатия в ZRAM функционируют должным образом:

  1. Проверьте состояние устройства подложки:

    cat /sys/block/zram0/bd_stat
    
  2. Проверьте эффективность пересжатия, отслеживая файл /sys/block/zram0/mm_stat . Изменения в размерах сжатых данных должны отобразиться после циклов технического обслуживания.

Проверка обратной записи для каждого процесса

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

  • Проверьте вывод adb logcat -s mmd , чтобы увидеть журналы успешной записи или диагностику сбоев.

Типичные проблемы и диагностика

Ниже перечислены распространенные ошибки, с которыми может столкнуться пользователь:

  • WritebackDailyLimitExceeded : Эта ошибка указывает на то, что достигнут лимит mmd.zram.writeback.max_bytes_per_day . В этом случае mmd приостанавливает запись в режиме ожидания до тех пор, пока не будет продвинуто 24-часовое скользящее окно.
  • Process prefetch or writeback failed : эту ошибку можно увидеть в logcat при сбое ioctl. Распространенные причины включают:
    • EBADF или ESRCH : Целевой процесс завершился до того, как mmd смог передать pidfd ядру.
    • ENOSPC : Раздел резервного хранилища заполнен или очередь устройств цикла исчерпана.
  • ZRAM не настроен: Если mmd не удается настроить ZRAM при загрузке, это может быть связано с тем, что устаревшие скрипты swapon_all или скрипты инициализации поставщика заблокировали /dev/block/zram0 до того, как mmd смог выполнить свою работу.