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 systemie Linux. 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 Service (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 systemu Linux.

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 przekroczeniu tego limitu 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 do miejsca wymiany aplikacja może działać wolniej.

W skrajnych przypadkach, jeśli aplikacja nadal będzie przydzielać pamięć anonimową, a na urządzeniu zabraknie miejsca wymiany, aplikacja może nie być w stanie przydzielić pamięci i w rezultacie prawdopodobnie ulegnie awarii.

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 podstawowych funkcji systemu.

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

  • Procesy widoczne są postrzegane przez użytkownika, np. aktywności na pierwszym planie, usługi na pierwszym planie lub inne stany, w których użytkownik może zauważyć opóźnienia.

  • Procesy niewidoczne to procesy działające w tle, które nie wchodzą w interakcję z użytkownikiem i nie są dla niego widoczne.

W tabeli poniżej przedstawiamy 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 przechwytywanie profilu pamięci lub rejestrowanie 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.

Modyfikowanie konfiguracji

Aby zmienić limity w całym systemie:

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

Polecenia powłoki

Polecenie am memory-limiter umożliwia Tobie i deweloperom 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 przekroczenia limitu przez proces.
processes
Liczba monitorowanych procesów.

ignore

Podpolecenie ignore tymczasowo wyklucza z ograniczenia identyfikator 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.