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 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 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.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.
Modyfikowanie konfiguracji
Aby zmienić limity w całym systemie:
- Zmodyfikuj plik
/vendor/etc/memory-limiter-config.xml. - 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 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 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 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.