Ограничитель памяти

В Android 17 и более поздних версиях включен Memory Limiter — системная служба, которая отслеживает и ограничивает использование памяти процессами приложений с помощью Linux cgroup v2. Memory Limiter предотвращает непропорциональное потребление системной памяти отдельными приложениями, что снижает общую нагрузку на память и предотвращает агрессивное завершение критически важных процессов переднего плана и кэшированных процессов при нехватке памяти.

Механизм

Ограничитель памяти интегрируется со службой управления активностью (AMS) для отслеживания событий жизненного цикла процесса и изменений состояния. Ограничитель памяти обеспечивает соблюдение ограничений памяти, используя иерархию cgroup v2 ядра Linux.

Для поддержки ограничителя памяти ядро ​​устройства должно включить cgroup v2 и контроллер memory . В частности, эта служба зависит от следующих атрибутов:

memory.high
Мягкое ограничение. При его превышении процесс замедляется, и ядро ​​пытается заблаговременно освободить страницы памяти у этого процесса.
memory.swap.max
Ограничивает максимальный объем пространства подкачки (например, ZRAM), который может использовать процесс.

Влияние на приложения

Приложения, работающие в пределах установленных лимитов памяти, не затрагиваются ограничителем памяти.

Когда приложение превышает установленный лимит memory.high , ядро ​​вытесняет чистую память приложения, защищенную файлами, и выгружает неактивную анонимную память, чтобы приложение оставалось в пределах лимита. В результате этого вытеснения страниц и активности подкачки приложение может временно испытывать замедление выполнения, но оно продолжает работать.

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

Мониторинг процесса

По умолчанию ограничитель памяти отслеживает процессы приложений (UID >= 10000). Основные системные процессы исключены из этого списка для обеспечения стабильности системы.

Ограничитель памяти устанавливает лимиты памяти на основе состояния видимости процесса:

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

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

В следующей таблице приведено соответствие конкретных состояний процесса классификации ограничений памяти:

Состояние процесса Ограничение памяти
PERSISTENT Без ограничений
PERSISTENT_UI Без ограничений
TOP Видимый
BOUND_TOP Видимый
FOREGROUND_SERVICE Не видно
BOUND_FOREGROUND_SERVICE Не видно
IMPORTANT_FOREGROUND Видимый
IMPORTANT_BACKGROUND Не видно
TRANSIENT_BACKGROUND Не видно
BACKUP Не видно
SERVICE Не видно
RECEIVER Не видно
TOP_SLEEPING Видимый
HEAVY_WEIGHT Не видно
HOME Не видно
LAST_ACTIVITY Не видно
CACHED_ACTIVITY Кэшировано
CACHED_ACTIVITY_CLIENT Кэшировано
CACHED_RECENT Кэшировано
CACHED_EMPTY Кэшировано

В кэшированном состоянии процессы замораживаются, а затем максимально освобождаются.

Когда процесс превышает установленный для него лимит memory.high , ограничитель памяти обнаруживает это событие и может запустить диагностические действия, такие как создание профиля памяти или запись аномалии в statsd .

Конфигурация

Ограничитель памяти считывает свою конфигурацию из раздела vendor :

  • Путь к файлу: /vendor/etc/memory-limiter-config.xml

формат XML

Конфигурационный файл соответствует схеме, определенной в memory-limiter-config.xsd . В файле определены несколько наборов ограничений, упорядоченных по доступной памяти; служба выбирает наиболее подходящий набор ограничений на основе доступной оперативной памяти устройства. Все значения памяти указываются в мебибайтах (МиБ).

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <!-- RAM minimums account for MemTotal excluding carve-outs. -->
    <limitSet>
      <!-- Limits for 16GB RAM device (MemTotal >= 15GiB): 10G/5G/5G/5G -->
      <minimumRequiredMemTotal>15360</minimumRequiredMemTotal>
      <memVisible>10240</memVisible>
      <memNotVisible>5120</memNotVisible>
      <swapVisible>5120</swapVisible>
      <swapNotVisible>5120</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 12GB RAM device (MemTotal >= 11GiB): 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>11264</minimumRequiredMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 8GB RAM device (MemTotal >= 7GiB): 5G/3G/3G/3G -->
      <minimumRequiredMemTotal>7168</minimumRequiredMemTotal>
      <memVisible>5120</memVisible>
      <memNotVisible>3072</memNotVisible>
      <swapVisible>3072</swapVisible>
      <swapNotVisible>3072</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 6GB RAM device (MemTotal >= 5GiB): 4G/2G/2G/2G -->
      <minimumRequiredMemTotal>5120</minimumRequiredMemTotal>
      <memVisible>4096</memVisible>
      <memNotVisible>2048</memNotVisible>
      <swapVisible>2048</swapVisible>
      <swapNotVisible>2048</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 4GB RAM device (MemTotal >= 3GiB): 2G/1G/1G/1G -->
      <minimumRequiredMemTotal>3072</minimumRequiredMemTotal>
      <memVisible>2048</memVisible>
      <memNotVisible>1024</memNotVisible>
      <swapVisible>1024</swapVisible>
      <swapNotVisible>1024</swapNotVisible>
    </limitSet>
  </configList>
</MemoryLimiterConfig>
version
Положительное целое число, указывающее на версию конфигурации. Оно должно быть 1 .
minimumRequiredMemTotal

Минимальный MemTotal системы (в МиБ), необходимый для применения этого ограничения. Служба сравнивает это значение с общим объемом доступной памяти, сообщаемым ядром в файле /proc/meminfo .

Понимание выделения памяти: значение MemTotal ядра отражает объем физической оперативной памяти, доступной операционной системе после вычета выделенной памяти для аппаратного и встроенного обеспечения. Выделенная память резервируется для специализированных аппаратных компонентов, таких как графический процессор, модем базовой полосы, процессор обработки изображений камеры, защищенные среды выполнения и гипервизоры, обычно занимая от 500 МиБ до более 1 ГиБ физической памяти.

Поскольку MemTotal меньше заявленного физического объема DRAM устройства, пороговые значения minimumRequiredMemTotal включают запас для этих ограничений. Например, для конфигурации, предназначенной для устройств с 16 ГБ памяти, значение minimumRequiredMemTotal составляет 15360 (15 ГиБ), а не 16384 (16 ГиБ), а для устройств с 12 ГБ памяти — 11264 (11 ГиБ). Это гарантирует, что каждое устройство будет соответствовать своему предполагаемому уровню независимо от различий в ограничениях на уровне платы.

memVisible

Мягкое ограничение памяти ( memory.high ) в МиБ применяется к видимым процессам.

memNotVisible

Мягкое ограничение на использование памяти ( memory.high ) в МиБ применяется к невидимым процессам.

swapVisible

Ограничение объема подкачки ( memory.swap.max ) в МиБ применяется к видимым процессам.

swapNotVisible

Ограничение на объем подкачки ( memory.swap.max ) в МиБ применяется к невидимым процессам.

Стандартные ограничения платформы

В Android 17 и более поздних версиях платформа задает стандартные ограничения на использование памяти и файла подкачки в файле /vendor/etc/memory-limiter-config.xml для всех распространенных уровней физической оперативной памяти:

Физическая оперативная память Минимально необходимые
MemTotal
(minimumRequiredMemTotal)
Ограничение видимой памяти
(memVisible)
Невидимый лимит памяти
(memNotVisible)
Видимый лимит свопа
(swapVisible)
Не отображается лимит свопа
(swapNotVisible)
16 Гб 15 360 МиБ (15 ГиБ) 10 240 МиБ (10 ГиБ) 5120 МиБ (5 ГиБ) 5120 МиБ (5 ГиБ) 5120 МиБ (5 ГиБ)
12 ГБ 11 264 МиБ (11 ГиБ) 8192 МиБ (8 ГиБ) 4096 МиБ (4 ГиБ) 4096 МиБ (4 ГиБ) 4096 МиБ (4 ГиБ)
8 ГБ 7168 МиБ (7 ГиБ) 5120 МиБ (5 ГиБ) 3072 МиБ (3 ГиБ) 3072 МиБ (3 ГиБ) 3072 МиБ (3 ГиБ)
6 ГБ 5120 МиБ (5 ГиБ) 4096 МиБ (4 ГиБ) 2048 МиБ (2 ГиБ) 2048 МиБ (2 ГиБ) 2048 МиБ (2 ГиБ)
4ГБ 3072 МиБ (3 ГиБ) 2048 МиБ (2 ГиБ) 1024 МиБ (1 ГиБ) 1024 МиБ (1 ГиБ) 1024 МиБ (1 ГиБ)

Принципы ограничения памяти

Конфигурация ограничителя памяти разработана на основе следующих принципов платформы:

  • Согласованность экосистемы и совместимость приложений: единые ограничения памяти на разных устройствах обеспечивают предсказуемую производительность приложений во всей экосистеме Android. Приложения разрабатываются и тестируются в соответствии со стандартными требованиями к памяти; поддержание единых ограничений платформы предотвращает неожиданное снижение производительности или преждевременное завершение работы.

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

    • Видимые процессы: Выделено примерно от 1/2 до 2/3 общего объема физической оперативной памяти для поддержки активных задач пользовательского интерфейса, композиции и рендеринга.
    • Невидимые процессы: для фоновых задач выделено приблизительно от 1/4 до 1/3 от общего объема физической оперативной памяти.
  • Универсальная применимость: ограничения применяются единообразно ко всем процессам приложений на устройстве (UID >= 10000), включая предустановленные системные и OEM-приложения. Ограничитель памяти не поддерживает списки разрешенных приложений для исключения определенных приложений, обеспечивая справедливое управление памятью для всех приложений.

  • Отсутствие API для запросов во время выполнения: в Android 17 и выше приложения не могут программно запрашивать выделенные им лимиты памяти во время выполнения. Стандартные лимиты платформы определены с запасом, так что корректно работающие приложения функционируют без ограничений в обычном режиме.

  • Динамика высвобождения памяти и подкачки ядра: Когда процесс приложения приближается к своему пределу memory.high , ядро ​​Linux направляет высвобождение памяти непосредственно в группу процессов этого приложения (cgroup). Это включает в себя удаление неактивных страниц, хранящихся в файлах, и подкачку «холодных» анонимных страниц в ZRAM, поддерживая плавность работы системы без создания глобальной нагрузки на память.

Команды оболочки

Команда am memory-limiter позволяет разработчикам и системным интеграторам взаимодействовать со службой во время выполнения для разработки, тестирования и отладки:

am memory-limiter <SUB-COMMAND>

статус

Подкоманда status отображает рабочее состояние и активные метрики ограничителя памяти:

adb shell am memory-limiter status

Пример выходных данных:

Memory limiter
  enabled                  monitoring=true          ignored=none
  visibleMem=1948MB        visibleSwap=974MB
  notVisibleMem=974MB      notVisibleSwap=487MB
  started=36               watched=36               watch-failed=0
  events=0                 processes=36             process-hwm=36

Ключевые поля в выходных данных включают:

monitoring
Указывает, отслеживает ли ограничитель памяти активно процессы.
visibleMem и notVisibleMem
Вычисленные абсолютные пределы объема памяти ( memory.high ), применяемые в настоящее время для каждого состояния видимости.
visibleSwap и notVisibleSwap
Рассчитанные абсолютные лимиты обмена ( memory.swap.max ), действующие в настоящее время для каждого состояния видимости.
events
Количество раз, когда процесс превысил установленный для него лимит.
processes
Текущее количество отслеживаемых процессов.

игнорировать

Подкоманда ignore временно исключает определенный UID или все процессы из ограничения памяти. Это полезно для сравнения производительности, стресс-тестирования или диагностики поведения памяти:

# Ignore a specific UID
adb shell am memory-limiter ignore 10087
# Ignore all processes (temporarily disables limiting)
adb shell am memory-limiter ignore all
# Resume normal limiting operation
adb shell am memory-limiter ignore none

руководство

Вспомогательная команда ` manual переопределяет вычисленные ограничения для конкретного процесса по идентификатору процесса (PID) с помощью пользовательского абсолютного значения в байтах. Значение должно быть целым числом, но может включать суффикс MB для обозначения MiB или суффикс GB для обозначения GiB:

# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1073741824
# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1024MB
# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1GB
# Remove the manual override for PID 1234
adb shell am memory-limiter manual 1234 none

Ручные настройки применяются только в течение времени жизни конкретного экземпляра процесса. Если процесс перезапускается, он возвращается к стандартным ограничениям, основанным на его состоянии.

При ручном управлении невозможно превысить физические ограничения системы.