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 procesu | Limit pamięci |
|---|---|
PERSISTENT | Bez ograniczeń |
PERSISTENT_UI | Bez ograniczeń |
TOP | Widoczne |
BOUND_TOP | Widoczne |
FOREGROUND_SERVICE | Niewidoczne |
BOUND_FOREGROUND_SERVICE | Niewidoczne |
IMPORTANT_FOREGROUND | Widoczne |
IMPORTANT_BACKGROUND | Niewidoczne |
TRANSIENT_BACKGROUND | Niewidoczne |
BACKUP | Niewidoczne |
SERVICE | Niewidoczne |
RECEIVER | Niewidoczne |
TOP_SLEEPING | Widoczne |
HEAVY_WEIGHT | Niewidoczne |
HOME | Niewidoczne |
LAST_ACTIVITY | Niewidoczne |
CACHED_ACTIVITY | W pamięci podręcznej |
CACHED_ACTIVITY_CLIENT | W pamięci podręcznej |
CACHED_RECENT | W pamięci podręcznej |
CACHED_EMPTY | W 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.xmlKonfiguracja 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:
- Zmodyfikuj plik
/vendor/etc/memory-limiter-config.xml. - 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 statusPrzykł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.
visibleMeminotVisibleMem- 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 UIDadb 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 1234adb 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.