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 w Linuksie w wersji 2. Ogranicznik pamięci zapobiega nadmiernemu wykorzystywaniu pamięci systemowej przez poszczególne aplikacje, 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 jest zintegrowany 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 w wersji 2 i kontroler memory. Usługa korzysta w szczególności z tych atrybutów:

memory.high
Limit elastyczny. Gdy limit zostanie przekroczony, proces jest ograniczany, a jądro próbuje odzyskać z niego pamięć.
memory.swap.max
Ogranicza ilość miejsca wymiany, z którego 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 plikowej dane aplikacji i zastąpi je danymi anonimowymi, aby utrzymać aplikację w ramach limitu. W wyniku usunięcia i zamiany aplikacja może działać wolniej.

W ekstremalnych przypadkach, jeśli aplikacja nadal przydziela pamięć anonimową, a na urządzeniu zabraknie miejsca na wymianę, może jej się nie udać przydzielić pamięci, co prawdopodobnie spowoduje awarię.

Monitorowanie procesów

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

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

  • Widoczne procesy są zauważalne dla użytkownika, np. aktywności na pierwszym planie, usługi na pierwszym planie lub inne stany, w których występuje zacinanie.

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

W tabeli poniżej znajdziesz 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 buforowania procesy są zamrażane, a następnie maksymalnie odzyskiwane.

Gdy proces przekroczy przypisany limit memory.high, narzędzie Memory Limiter wykryje to zdarzenie i może wywołać działania debugowania, takie jak przechwytywanie profilu pamięci lub rejestrowanie anomalii w statsd.

Konfiguracja

Skonfiguruj ogranicznik pamięci za pomocą pliku XML znajdującego się na vendor partycji. Konfiguracja umożliwia dostosowanie bezwzględnych limitów pamięci na podstawie konkretnych ograniczeń pamięci urządzenia.

  • Ścieżka 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 najlepiej dopasowany zestaw na podstawie dostępnej pamięci RAM urządzenia. Wszystkie wartości pamięci są podawane 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 limit był ważny.
memVisible
Limit pamięci (memory.high) dozwolony w przypadku widocznych procesów.
memNotVisible
Limit pamięci (memory.high) dozwolony dla niewidocznych procesów.
swapVisible
Limit pamięci wymiany (memory.swap.max) dozwolony w przypadku widocznych procesów.
swapNotVisible
Limit wymiany (memory.swap.max) dozwolony w przypadku niewidocznych procesów.

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

Podczas konfigurowania limitów pamięci na urządzeniu weź pod uwagę te wytyczne:

  • Dostosowywanie limitów do możliwości sprzętowych: producenci OEM mogą ustawiać limity dostosowane do możliwości sprzętowych urządzenia. Android zaleca te zakresy:

    • Widoczne procesy: co najmniej 1/2 i co najwyżej 2/3 całkowitej pamięci RAM.
    • Procesy niewidoczne: od 1/4 do 1/3 całej pamięci RAM. Producenci OEM mogą podejmować różne decyzje w zależności od możliwości urządzenia i przypadków użycia.
  • Brak interfejsu API środowiska wykonawczego dla aplikacji: od Androida 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 ich w rozsądnych przypadkach użycia.

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

Modyfikowanie konfiguracji

Aby zmienić limity w całym systemie, wykonaj te czynności:

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

Polecenia powłoki

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

am memory-limiter <SUB-COMMAND>

status

Podpolecenie status podaje stan 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 to:

monitoring
Wskazuje, czy ogranicznik aktywnie monitoruje procesy.
visibleMem i notVisibleMem
Podaj 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.

ignoruj

Podpolecenie ignore tymczasowo wyklucza identyfikator UID lub wszystkie procesy z ograniczeń. To działanie jest przydatne podczas testów 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

ręczny

Podpolecenie manual zastępuje obliczone limity dla określonego 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ąpienia są stosowane tylko w cyklu życia procesu. Jeśli proces zostanie ponownie uruchomiony, zostaną przywrócone domyślne limity w zależności od stanu.