В Android 17 и более поздних версиях поддерживается демон управления памятью (mmd) – системный демон, который обрабатывает конфигурацию демона, настраиваемые параметры и текущие задачи по обслуживанию файла подкачки или ZRAM.
Фон
До появления mmd конфигурации ZRAM в Android были фрагментированы и предлагали ограниченные возможности настройки. mmd решает эту проблему, централизуя управление ZRAM, позволяя использовать более сложную логику конфигурации и упрощая добавление новых функций и улучшений архитектуры.
mmd также обеспечивает четкое разделение задач между процессом на основе Java system_server и подкачкой или управлением памятью на уровне ядра.
Архитектура и управление 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.

Рисунок 1. Схема планирования обслуживания ZRAM.
- Планировщик.
ZramMaintenanceрегистрирует периодическую фоновую задачу вJobSchedulerAndroid. - Ограничения для заданий. Чтобы предотвратить заикание интерфейса и конфликты ЦП, для задания явно заданы значения
setRequiresDeviceIdle(true)иsetRequiresBatteryNotLow(true). - Триггер Binder. Когда планировщик запускает
onStartJob(),system_serverвызываетmmd.doZramMaintenanceAsync(). Это односторонний асинхронный вызов Binder.system_serverне блокирует ожидание завершения очистки.mmdставит эту задачу в очередь фонового потока, чтобы выполнить повторное сжатие и запись последовательно.
Обратная запись для каждого процесса
Удаление памяти на уровне отдельных процессов управляется сервисом ActivityManagerService с помощью функции
com.android.server.am.CachedAppOptimizer.

Рисунок 2. Процесс обратной записи mmd.
Когда процесс переходит в фоновое кешированное состояние, ActivityManager выполняет сжатие памяти. Если завершение процесса из-за нехватки памяти будет заметно пользователю (то есть процесс размещает Activity) и если запись в ZRAM для каждого процесса приведет к тому, что объем памяти, занимаемый процессом, будет близок к нулю, система выполняет следующие действия:
- После сжатия
CachedAppOptimizerотправляет отложенное сообщение (ZRAM_WRITEBACK_MSG) своему внутреннему обработчику сжатия (с задержкой наmZramWritebackWaitSeconds). - Когда задержка закончится, ActivityManager откроет дескриптор файла безопасного процесса
pidfd. - Сервер системы вызывает
mmd.asyncWritebackProcessZramMemory(pfd, callback). mmdвыполняет ioctl для обратной записи на процесс и отправляет отчет с помощьюIMmdProcessWritebackCallback. Если все пройдет успешно, ActivityManager пометит запись процесса (setIsZramWrittenBack(app, true)), чтобы повысить приоритет процессаoom_score_adj, и запишет показатели вFrameworkStatsLog.ZRAM_WRITEBACK_EVENT.
Упреждающий запрос для каждого процесса
Когда пользователь перезапускает ранее кешированное приложение (размороженное из-за UNFREEZE_REASON_ACTIVITY), ActivityManager минимизирует задержку запуска приложения, вызванную серьезными ошибками страниц из резервного хранилища:
CachedAppOptimizerперехватывает событие разморозки и вызываетprefetchZram(app).- Системный сервер отправляет
pidfdприложения через Binder, используяmmd.asyncPrefetchProcessZramMemory(pfd).mmdвыполняет ioctlZRAM_ANDROID_IOC_PROCESS_PREFETCH, указывая ядру асинхронно предварительно загружать страницы подкачки обратно в ОЗУ, пока инициализируется основной поток пользовательского интерфейса приложения.
Обзор задач по обслуживанию и постобработке
В этом разделе описываются фоновые операции обслуживания и задачи постобработки, которые mmd выполняет для оптимизации swap-пространства и системной памяти.
Техническое обслуживание в mmd
В mmd обслуживание – это запланированные фоновые проверки, которые оптимизируют использование swap-пространства и физической памяти, не влияя на производительность активных приложений. Вместо того чтобы выполнять непрерывные синхронные проверки (которые приводили бы к частым пробуждениям ЦП и временным зависаниям интерфейса), обслуживание выполняется асинхронно:
system_serverпериодически запускаетdoZramMaintenanceAsync()в Binder.mmdпомещает запрос в очередь фоновых задачLowPrioWorkItem::ZramMaintenance.В
mmdесть один рабочий поток, который управляет очередью с высоким и низким приоритетом. Задачи с высоким приоритетом (например, предварительная выборка для каждого процесса) обрабатываются первыми и могут вытеснять задачи с низким приоритетом. Обслуживание и запись данных на уровне процессов выполняются как задачи с низким приоритетом. После извлечения из очереди рабочий поток выполняет две основные операции обслуживания последовательно:Повторное сжатие ZRAM. Проверяет существующие страницы подкачки и повторно сжимает неактивные страницы с помощью вторичного алгоритма с более высоким коэффициентом сжатия, например
zstd.ZRAM writeback. Сканирует неактивные страницы и полностью удаляет их из ОЗУ на резервное флеш-хранилище, представляющее собой петлевое устройство из файла на
/data.
Задачи постобработки в ZRAM
В модуле ZRAM ядра Linux и архитектуре mmd задачи постобработки – это асинхронные преобразования, применяемые к страницам памяти после того, как они уже были выгружены стандартными путями восстановления ядра (kswapd или сжатие).
Когда страница впервые выгружается из памяти, система отдает приоритет скорости: она использует быстрый основной алгоритм сжатия (например, lz4) и сохраняет сжатую страницу в ОЗУ. Однако со временем многие страницы, перенесенные в файл подкачки, становятся холодными или неактивными, например приложения, которые были помещены в кеш в фоновом режиме и не запускались в течение нескольких часов. Оставлять неиспользуемые страницы в быстрой, слабо сжатой ZRAM неэффективно.
Конвейер постобработки
mmd использует многоэтапный жизненный цикл постобработки для оптимизации этих страниц:

Рисунок 3. mmd жизненный цикл страницы.
Этап 1. Исходная замена (быстрое сжатие). Память освобождается с помощью kswapd или сжатия приложений. Обычно при первом восстановлении используется быстрый алгоритм сжатия, например
lz4, а содержимое хранится в ОЗУ.Этап 2. Отметка неактивности (старение и отслеживание). Отслеживание неактивности обращается к отслеживанию памяти ядра (
CONFIG_ZRAM_TRACK_ENTRY_ACTIME) или использует свой программный маркер неактивности, чтобы отслеживать, как долго страницы остаются без изменений.mmdЭтап 3. Постобработка 1 – повторное сжатие (освобождение памяти): страницы, достигшие возраста бездействия повторного сжатия (от
min_idle_secondsдоmax_idle_seconds), подвергаются повторному сжатию.mmdзаписывает в/sys/block/zram0/recompressинструкцию для ядра о том, что страницуlz4нужно распаковать и снова сжать с помощьюzstd. Это позволяет освободить физическую память без износа флеш-памяти.Этап 4. Постобработка 2 – запись в память (выгрузка во флеш-память). Если нагрузка на память не снижается и страницы достигают возраста бездействия записи (обычно 20 часов или более),
mmdзапускает запись в память.mmdзаписывает в/sys/block/zram0/idleи/sys/block/zram0/writeback, чтобы полностью вытеснить сжатую страницу из ОЗУ в резервное флеш-хранилище.
Настройка ZRAM
mmd загружает и обрабатывает следующие свойства настройки ZRAM:
| Свойство | Использовать | По умолчанию |
|---|---|---|
mmd.zram.enabled |
Включена ли настройка ZRAM в mmd. |
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, то для настройки глубины очереди устройства петли, поддерживающего запись ZRAM, используется значение из mmd.zram.writeback.nr_tags. Это обходное решение для ситуаций, когда правила 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.sizemmd.zram.comp_algorithmmmd.zram.device_prioritymmd.zram.recompression.enabledmmd.zram.recompression.huge_idle.enabledmmd.zram.recompression.idle.enabledmmd.zram.recompression.huge.enabledmmd.zram.recompression.threshold_bytesmmd.zram.recompression.algorithmmmd.zram.writeback.device_sizemmd.zram.writeback.huge_idle.enabledmmd.zram.writeback.idle.enabledmmd.zram.writeback.huge.enabled
Прекращение поддержки существующей настройки ZRAM
Хотя swapon_all по-прежнему доступен в Android для настройки ZRAM и раздела подкачки на диске, mmd является предпочтительным подходом к управлению ZRAM, поскольку он обеспечивает более простую настройку и продвинутые функции, такие как повторное сжатие ZRAM.
Если mmd ZRAM включен mmd.zram.enabled:
- Настройка ZRAM в реализации
swapon_allстановится недействительной. - Существующие конфигурации ZRAM, например
config_zramWritebackв файле overlayconfig.xmlи системные свойства обратной записиro.zram.*, игнорируются.
Параметры настройки ZRAM
Обслуживание ZRAM должно работать без дополнительных настроек, но вы можете настроить его с помощью системных свойств, описанных в этом разделе.
Планирование обслуживания ZRAM
Эти свойства определяют, как и когда system_server планирует задачи по обслуживанию ZRAM.
| Свойство | Использовать | По умолчанию |
|---|---|---|
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 maintenance отмечает страницы ZRAM как неактивные на основе того, сколько времени прошло с момента последнего доступа к ним. Для работы этой функции необходимо включить конфигурации ядра CONFIG_ZRAM_TRACK_ENTRY_ACTIME или CONFIG_ZRAM_MEMORY_TRACKING. CONFIG_ZRAM_TRACK_ENTRY_ACTIME включен по умолчанию в ядрах GKI 6.18 и более поздних версий. В более ранних версиях ядра она не включена по умолчанию и требует дополнительных ресурсов памяти.
Если конфигурация ядра не включена, mmd обслуживание ZRAM переходит на программный заменитель для отслеживания неактивных страниц ZRAM:
Отметить все страницы ZRAM как неактивные при запуске
mmd.Пропускать следующие проверки ZRAM, пока не пройдет необходимый период отсрочки.
Запись в zRAM или повторное сжатие неактивных страниц. Если из-за ограничений на запись остаются неактивные страницы,
mmdпродолжает записывать страницы при следующем техническом обслуживании, не отмечая новые страницы как неактивные (пропуская шаг 4).Если все неактивные страницы были записаны, снова пометьте все страницы ZRAM как неактивные и вернитесь к шагу 2. Если запись в ZRAM отключена,
mmdпомечает все страницы ZRAM как неактивные, когда после периода неактивности происходит повторное сжатие ZRAM.
Устранение неполадок и проверка
Чтобы проверить и диагностировать работу mmd и ZRAM, выполните следующие действия по проверке и устранению неполадок.
Как проверить настройки ZRAM
Чтобы проверить, успешно ли mmd настроил ZRAM во время загрузки:
Проверьте активный алгоритм сжатия и размер диска:
cat /sys/block/zram0/comp_algorithm cat /sys/block/zram0/disksizeПроверьте системные свойства
mmdи статус запущенного сервиса:getprop | grep mmd.zram dumpsys -l | grep mmd
Как проверить обслуживание и запись ZRAM
Убедитесь, что задачи обратной записи и повторного сжатия ZRAM работают:
Проверьте статус базового блочного устройства:
cat /sys/block/zram0/bd_statПроверьте эффективность повторного сжатия, отслеживая
/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: раздел резервного хранилища заполнен или очередь устройства loop исчерпана.
- ZRAM не настроен. Если
mmdне удается настроить ZRAM при загрузке, возможно, устаревшие скриптыswapon_allили скрипты инициализации поставщика заблокировали/dev/block/zram0до того, какmmdсмог выполниться.