Ogranicznik pamięci

Android 17 i nowsze wersje obsługują ogranicznik pamięci, czyli usługę systemową, która monitoruje i ogranicza wykorzystanie pamięci przez procesy aplikacji za pomocą cgroup v2 w Linuksie. Ogranicznik pamięci uniemożliwia poszczególnym aplikacjom zużywanie nadmiernej ilości pamięci systemowej, co zmniejsza obciążenie pamięci w całym systemie i zapobiega agresywnemu zamykaniu krytycznych procesów z powodu braku pamięci.

Mechanizm

Ogranicznik pamięci integruje się z usługą Activity Manager (AMS), aby śledzić zdarzenia cyklu życia procesu i zmiany stanu. Ogranicznik pamięci wymusza limity pamięci za pomocą systemu plików cgroup v2 jądra Linuksa.

Aby korzystać z ogranicznika pamięci, jądro urządzenia musi obsługiwać cgroup v2 i kontroler memory. Usługa opiera się w szczególności na tych atrybutach:

memory.high
Limit. Po jego przekroczeniu proces jest ograniczany, a jądro próbuje odzyskać z niego pamięć.
memory.swap.max
Ogranicza ilość miejsca wymiany, z której może korzystać proces.

Wpływ na aplikacje

Aplikacje, które nie przekraczają limitów pamięci, nie są objęte działaniem ogranicznika pamięci.

Gdy aplikacja przekroczy limit memory.high, jądro usunie z pamięci pliki aplikacji i przeniesie jej pamięć anonimową do miejsca wymiany, aby utrzymać aplikację w limicie. W wyniku usunięcia i przeniesienia aplikacja może działać wolniej.

W skrajnych przypadkach, jeśli aplikacja nadal przydziela pamięć anonimową, a na urządzeniu zabraknie miejsca wymiany, aplikacja może nie być w stanie przydzielić pamięci, co prawdopodobnie spowoduje jej awarię.

Monitorowanie procesów

Ogranicznik pamięci domyślnie monitoruje procesy aplikacji (UID >= 10000). Procesy systemowe są zwykle wyłączone z monitorowania, aby pomóc w weryfikacji stabilności podstawowego systemu.

Ogranicznik pamięci przypisuje limity pamięci na podstawie stanu procesu:

  • Procesy widoczne są w stanie, w którym mogą wyświetlać interfejs użytkownika. Podczas wyświetlania interfejsu użytkownika proces może używać większego zestawu roboczego pamięci RAM, dlatego ma bardziej liberalny limit pamięci.

  • Procesy niewidoczne są w stanie, w którym aktywnie wykonują zadania, ale nie wyświetlają interfejsu użytkownika. Używają pamięci do wykonywania tych zadań, ale w mniejszym stopniu niż podczas wyświetlania interfejsu użytkownika, dlatego mają bardziej restrykcyjny limit.

W tabeli poniżej przedstawiono mapowanie konkretnych stanów procesu na limity pamięci:

Stan procesuLimit pamięci
PERSISTENTBez ograniczeń
PERSISTENT_UIBez ograniczeń
TOPWidoczne
BOUND_TOPWidoczne
FOREGROUND_SERVICENiewidoczne
BOUND_FOREGROUND_SERVICENiewidoczne
IMPORTANT_FOREGROUNDWidoczne
IMPORTANT_BACKGROUNDNiewidoczne
TRANSIENT_BACKGROUNDNiewidoczne
BACKUPNiewidoczne
SERVICENiewidoczne
RECEIVERNiewidoczne
TOP_SLEEPINGWidoczne
HEAVY_WEIGHTNiewidoczne
HOMENiewidoczne
LAST_ACTIVITYNiewidoczne
CACHED_ACTIVITYW pamięci podręcznej
CACHED_ACTIVITY_CLIENTW pamięci podręcznej
CACHED_RECENTW pamięci podręcznej
CACHED_EMPTYW pamięci podręcznej

W stanie w pamięci podręcznej procesy są zamrażane, a następnie maksymalnie odzyskiwane.

Gdy proces przekroczy przypisany limit memory.high, ogranicznik pamięci wykryje to zdarzenie i może wywołać działania związane z debugowaniem, takie jak przechwycenie profilu pamięci lub zalogowanie anomalii w statsd.

Konfiguracja

Ogranicznik pamięci skonfiguruj za pomocą pliku XML znajdującego się w partycji vendor. Konfiguracja pozwala dostosować bezwzględne limity pamięci na podstawie konkretnych ograniczeń pamięci urządzenia.

  • Ścieżka do pliku: /vendor/etc/memory-limiter-config.xml

  • Konfiguracja domyślna: jeśli plik konfiguracji nie zostanie znaleziony lub będzie nieczytelny albo nieprawidłowy, ogranicznik pamięci zostanie wyłączony.

Format XML

Plik konfiguracji jest zgodny ze schematem zdefiniowanym w memory-limiter-config.xsd. Plik umożliwia zdefiniowanie wielu zestawów limitów. Usługa wybiera najlepsze dopasowanie na podstawie dostępnej pamięci RAM urządzenia. Wszystkie wartości pamięci są zdefiniowane w mebibajtach (MiB).

<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
Dodatnia liczba całkowita identyfikująca wersję konfiguracji. Musi to być 1.
minimumRequiredMemTotal
Minimalna wymagana ilość dostępnej pamięci systemowej, aby ten zestaw limitów był prawidłowy.
memVisible
Limit pamięci (memory.high) dozwolony dla procesów widocznych.
memNotVisible
Limit pamięci (memory.high) dozwolony dla procesów niewidocznych.
swapVisible
Limit miejsca wymiany (memory.swap.max) dozwolony dla procesów widocznych.
swapNotVisible
Limit miejsca wymiany (memory.swap.max) dozwolony dla procesów niewidocznych.

Wskazówki dotyczące limitu pamięci urządzenia

Podczas konfigurowania limitów pamięci urządzenia weź pod uwagę te wskazówki:

  • Dostosuj limity do możliwości sprzętowych: producenci OEM mogą ustawiać limity dostosowane do możliwości sprzętowych swoich urządzeń. Android zaleca te zakresy:

    • Procesy widoczne: co najmniej połowa i co najwyżej 2/3 całkowitej fizycznej pamięci RAM.
    • Procesy niewidoczne: od 1/4 do 1/3 całkowitej fizycznej pamięci RAM. Producenci OEM mogą podejmować różne decyzje na podstawie możliwości urządzenia i przypadków użycia.
  • Brak interfejsu API środowiska wykonawczego dla aplikacji: w Androidzie 17 (SDK 37) aplikacje nie mają interfejsu API do sprawdzania limitów pamięci w czasie działania. Producenci OEM powinni wziąć to pod uwagę i unikać ustawiania zbyt niskich limitów, aby aplikacje nie osiągały limitów w rozsądnych przypadkach użycia.

  • Konfiguracja uniwersalna: limity dotyczą wszystkich procesów aplikacji na urządzeniu, w tym aplikacji preinstalowanych. Nie ma listy dozwolonych, która wyłączałaby niektóre aplikacje z tych limitów.

Modyfikowanie konfiguracji

Aby zmienić limity w całym systemie:

  1. Zmodyfikuj plik /vendor/etc/memory-limiter-config.xml.
  2. Aby zmiany zaczęły obowiązywać, uruchom ponownie urządzenie lub usługę system_server.

Polecenia powłoki

Polecenie am memory-limiter umożliwia Tobie i programistom interakcję z usługą w czasie działania na potrzeby programowania i testowania:

am memory-limiter <SUB-COMMAND>

status

Podpolecenie status informuje o stanie działania ogranicznika pamięci:

adb shell am memory-limiter status

Przykładowe dane wyjściowe:

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

Kluczowe pola w danych wyjściowych:

monitoring
Wskazuje, czy ogranicznik aktywnie obserwuje procesy.
visibleMem i notVisibleMem
Wskazują obliczone bezwzględne limity pamięci dla każdego stanu.
events
Liczba przypadków, w których proces przekroczył limit.
processes
Liczba monitorowanych procesów.

ignore

Podpolecenie ignore tymczasowo wyklucza z limitu UID lub wszystkie procesy. Ta czynność jest przydatna podczas testowania wydajności lub gdy chcesz zezwolić konkretnej aplikacji na przekroczenie limitów.

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

Podpolecenie manual zastępuje obliczone limity dla konkretnego procesu (według identyfikatora procesu lub PID) niestandardową wartością bezwzględną w megabajtach (MB):

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

Ręczne zastępowanie zdarzeń dotyczy tylko cyklu życia procesu. Jeśli proces zostanie ponownie uruchomiony, powróci do domyślnych limitów na podstawie swojego stanu.