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

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

Механизм

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

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

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

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

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

Когда приложение превышает установленный лимит 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 , Memory Limiter обнаруживает это событие и может запустить действия по отладке, такие как создание профиля памяти или запись аномалии в statsd .

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

Настройте ограничитель памяти с помощью XML-файла, расположенного в разделе vendor . Настройка позволяет задать абсолютные пределы памяти в зависимости от конкретных ограничений памяти устройства.

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

  • Конфигурация по умолчанию: если файл конфигурации не найден, недоступен для чтения или недействителен, ограничитель памяти отключается.

формат XML

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

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <limitSet>
      <!-- Limits for a phone with at least 14G of ram: 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
  </configList>
</MemoryLimiterConfig>
version
Положительное целое число, указывающее версию конфигурации. Должно быть равно 1.
minimumRequiredMemTotal
Минимальный объем доступной системной памяти, необходимый для корректной работы данного ограничения.
memVisible
Ограничение памяти ( memory.high ) позволяло отображать процессы.
memNotVisible
Ограничение памяти ( memory.high ) позволяло запускать невидимые процессы.
swapVisible
Ограничение на объем файла подкачки ( memory.swap.max ) позволяло отображать процессы, находящиеся в видимом режиме.
swapNotVisible
Ограничение на объем файла подкачки ( memory.swap.max ) позволяло запускать невидимые процессы.

Изменить конфигурацию

Чтобы изменить общесистемные ограничения, выполните следующие действия:

  1. Измените файл /vendor/etc/memory-limiter-config.xml .
  2. Для вступления изменений в силу перезагрузите устройство или перезапустите system_server .

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

Команда 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
Укажите рассчитанные абсолютные пределы объема памяти для каждого состояния.
events
Количество раз, когда процесс превысил свой лимит.
processes
Количество отслеживаемых процессов.

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

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

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

руководство

manual команда `handle` переопределяет рассчитанные ограничения для конкретного процесса (по идентификатору процесса, или PID) пользовательским абсолютным значением в мегабайтах (МБ):

adb shell am memory-limiter manual 1234 1024   // Set a 1024 MB limit for PID 1234
adb shell am memory-limiter manual 1234 none // Remove the manual override for PID 1234

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