Demon LMK (lmkd
) w Androidzie monitoruje stan pamięci uruchomionego systemu Androida i reaguje na wysokie obciążenie pamięci, zamykając procesy najmniej istotne dla utrzymania akceptowalnego poziomu wydajności systemu.
Informacje o obciążeniu pamięci
System Android, który równolegle wykonuje wiele procesów, może napotkać sytuacje, gdy wyczerpuje się pamięć systemowa, a procesy wymagające więcej pamięci mogą odczuwać zauważalne opóźnienia. Napięcie pamięci to stan, w którym systemowi brakuje pamięci. Aby zmniejszyć to napięcie, Android musi zwolnić pamięć, ograniczając lub zamykając nieistotne procesy, prosząc procesy o zwolnienie nieistotnych zasobów z pamięci podręcznej itd.
Wcześniej Android monitorował obciążenie pamięci systemowej za pomocą sterownika LMK (low memory killer) w jądrze, czyli sztywnego mechanizmu opartego na zakodowanych wartościach. Od jądra 4.12 sterownik LMK został usunięty z upstreamowego jądra, a zadania monitorowania pamięci i zabijania procesów wykonuje przestrzeń użytkownika lmkd
.
Informacje o zatrzymaniu spowodowanym przez spadek ciśnienia
Android 10 i nowsze wersje obsługują nowy tryb lmkd
, który wykorzystuje monitory PSI (pressure stall information) jądra do wykrywania nacisku pamięci. Zestaw poprawek PSI w rdzeniach upstream (przeniesionych do wersji 4.9 i 4.14) mierzy czas opóźnienia zadań spowodowany brakiem pamięci. Ponieważ te opóźnienia mają bezpośredni wpływ na wrażenia użytkownika, stanowią wygodny wskaźnik do określania stopnia obciążenia pamięci. Kernel upstream zawiera też monitory PSI, które umożliwiają uprzywilejowanym procesom w przestrzeni użytkownika (takim jak lmkd
) określanie wartości progowych opóźnień i subskrybowanie zdarzeń z jądra w przypadku przekroczenia wartości progowych.
Różnica między monitorowaniem PSI a vmpressure
Ponieważ sygnały vmpressure
(generowane przez jądro do wykrywania ciśnienia w pamięci i używane przez lmkd
) często zawierają wiele fałszywych wyników pozytywnych, lmkd
musi przeprowadzić filtrowanie, aby określić, czy pamięć jest pod prawdziwym ciśnieniem.
Powoduje to niepotrzebne lmkd
wybudzanie i używanie dodatkowych zasobów obliczeniowych. Korzystanie z monitorowania PSI skutkuje dokładniejszym wykrywaniem ciśnienia pamięci i minimalizuje narzut filtrowania.
Korzystanie z monitorów PSI
Aby zamiast zdarzeń vmpressure
używać monitorów PSI, skonfiguruj właściwość ro.lmk.use_psi
. Wartość domyślna to true
, co powoduje, że PSI monitoruje domyślny mechanizm wykrywania nacisku pamięci dla lmkd
. Monitory PSI wymagają obsługi przez jądro, dlatego jądro musi zawierać poprawki PSI i być skompilowane z włączoną obsługą PSI (CONFIG_PSI=y
).
Wady sterownika LMK w rdzeniu
Android wycofuje sterownik LMK z powodu kilku problemów, w tym:
- Urządzenia z małą ilością pamięci RAM wymagały agresywnego dostosowania, a nawet wtedy słabo sobie radziły z obciążeniami z dużą aktywną pamięcią podręczną pagecache obsługiwaną przez pliki. Złe wyniki spowodowały utratę kontroli i brak zabójstw.
- Sterownik jądra LMK korzystał z limitów wolnej pamięci bez skalowania na podstawie obciążenia pamięci.
- Ze względu na sztywność projektu partnerzy często dostosowywali sterownik, aby działał na ich urządzeniach.
- Sterownik LMK był podłączony do interfejsu API do kompresji bloków, który nie był przeznaczony do wykonywania czasochłonnych operacji, takich jak wyszukiwanie celów i ich zabijanie, co spowalniało proces
vmscan
.
Userspace lmkd
Przestrzeń użytkownika lmkd
realizuje te same funkcje co sterownik w jądrze, ale do wykrywania i szacowania obciążenia pamięci używa istniejących mechanizmów jądra. Takie mechanizmy obejmują korzystanie z generowanych przez jądro zdarzeń vmpressure
lub monitorów informacji o ciśnieniu (PSI) w celu otrzymywania powiadomień o poziomie ciśnienia w pamięci oraz korzystanie z funkcji cgroup pamięci w celu ograniczenia zasobów pamięci przydzielonych do każdego procesu na podstawie jego ważności.
Używanie lmkd w przestrzeni użytkownika w Androidzie 10
W Androidzie 9 i nowszych przestrzeń użytkownika lmkd
jest aktywowana, jeśli nie wykryto sterownika LMK w rdzeniu. Ponieważ przestrzeń użytkownika lmkd
wymaga obsługi cgroup przez jądro, jądro musi zostać skompilowane z tymi ustawieniami konfiguracji:
CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
Zabijanie strategii
Userspace lmkd
obsługuje strategie zabijania na podstawie zdarzeń vmpressure
lub monitorów PSI, ich ważności i innych wskazówek, takich jak wykorzystanie swapa. Strategie zabijania różnią się w zależności od tego, czy urządzenie ma mało pamięci czy dużą wydajność:
- Na urządzeniach z małą ilością pamięci system powinien tolerować większy nacisk na pamięć jako normalny tryb działania.
- Na urządzeniach o wysokiej wydajności wykorzystanie pamięci należy traktować jako nieprawidłową sytuację i usuwać, zanim wpłynie na ogólną wydajność.
Strategię wykluczania możesz skonfigurować za pomocą usługi ro.config.low_ram
.
Userspace lmkd
obsługuje też tryb starszy, w którym podejmuje decyzje o zatrzymaniu procesu, używając tych samych strategii co sterownik LMK w rdzeniu (czyli progów wolnej pamięci i pliku pamięci podręcznej). Aby włączyć tryb starszy, ustaw właściwość ro.lmk.use_minfree_levels
na true
.
Konfigurowanie lmkd
Skonfiguruj lmkd
na konkretnym urządzeniu, używając tych właściwości.
Właściwość | Użyj | Domyślny |
---|---|---|
ro.config.low_ram
|
Określ, czy urządzenie ma małą ilość pamięci RAM, czy jest to urządzenie o wysokiej wydajności. | false
|
ro.lmk.use_psi |
Używaj monitorów PSI (zamiast zdarzeń vmpressure ). |
true |
ro.lmk.use_minfree_levels
|
Używaj progów wolnej pamięci i pliku pamięci podręcznej do podejmowania decyzji o zabiciu procesu (czyli dopasowywania funkcji do jądra sterownika LMK). | false
|
ro.lmk.low
|
Minimalna wartość oom_adj procesów kwalifikujących się do zabijania na poziomie vmpressure .
|
1001 (wyłączona) |
ro.lmk.medium
|
Minimalny wynik oom_adj procesów kwalifikujących się do zabijania na średnim poziomie vmpressure .
|
800 (przechowywane w pamięci podręcznej lub nieistotne usługi) |
ro.lmk.critical
|
Minimalny wynik oom_adj procesów kwalifikujących się do zabijania na poziomie krytycznym vmpressure .
|
0 (dowolny proces) |
ro.lmk.critical_upgrade
|
Włącz uaktualnienie do poziomu krytycznego. | false
|
ro.lmk.upgrade_pressure
|
Maksymalna liczba mem_pressure , przy której poziom jest ulepszany, ponieważ system zbyt często przełącza się między poziomami.
|
100 (wyłączona) |
ro.lmk.downgrade_pressure
|
Minimalna wartość mem_pressure , przy której zdarzenie vmpressure jest ignorowane, ponieważ nadal jest wystarczająco dużo wolnej pamięci.
|
100 (wyłączona) |
ro.lmk.kill_heaviest_task
|
Zatrzymanie najbardziej obciążającego zadania (najlepsza decyzja) w porównaniu z dowolnym zadaniem (szybka decyzja). | false
|
ro.lmk.kill_timeout_ms
|
Czas w milisekundach po zabiciu, po którym nie będzie dokonywane żadne dodatkowe zabicie. | 0 (wyłączona) |
ro.lmk.debug
|
Włącz dzienniki debugowania lmkd .
|
false
|
Przykładowa konfiguracja urządzenia:
PRODUCT_PROPERTY_OVERRIDES += \
ro.lmk.low=1001 \
ro.lmk.medium=800 \
ro.lmk.critical=0 \
ro.lmk.critical_upgrade=false \
ro.lmk.upgrade_pressure=100 \
ro.lmk.downgrade_pressure=100 \
ro.lmk.kill_heaviest_task=true
LMKD w przestrzeni użytkownika w Androidzie 11
Android 11 ulepsza lmkd
, wprowadzając nową strategię zabijania procesów. Strategia zabijania używa mechanizmu PSI do wykrywania nacisku na pamięć, który został wprowadzony w Androidzie 10. lmkd
w Androidzie 11 uwzględnia poziomy wykorzystania zasobów pamięci i throttlingu, aby zapobiec niedoborowi pamięci oraz pogorszeniu wydajności.
Ta strategia zastępuje poprzednie strategie i może być stosowana zarówno na urządzeniach o wysokiej wydajności, jak i na urządzeniach z małą ilością pamięci RAM (Android Go).
Wymagania dotyczące jądra
W przypadku urządzeń z Androidem 11 lmkd
wymaga tych funkcji jądra:
- Dołącz poprawki PSI i włącz PSI (backporty dostępne w powszechnie używanych jądrach Androida 4.9, 4.14 i 4.19).
- Dołącz poprawki dotyczące obsługi PIDFD (poprawki dostępne w jądrach wspólnych Androida w wersjach 4.9, 4.14 i 4.19).
- W przypadku urządzeń z małą ilością pamięci RAM uwzględnij grupy pamięci.
jądro musi być skompilowane z tymi ustawieniami konfiguracji:
CONFIG_PSI=y
Konfigurowanie lmkd w Androidzie 11
Strategia zabijania pamięci w Androidzie 11 obsługuje ustawienia i wartości domyślne wymienione poniżej. Te funkcje działają zarówno na urządzeniach o wysokiej wydajności, jak i na urządzeniach z niewielką ilością pamięci RAM.
Właściwość | Użyj | Domyślny | |
---|---|---|---|
Wysoka wydajność | Mała ilość pamięci RAM | ||
ro.lmk.psi_partial_stall_ms |
Próg częściowego zablokowania PSI (w milisekundach) dla powiadomienia o niskiej pamięci. Jeśli urządzenie otrzymuje powiadomienia o niedostępności pamięci zbyt późno, zmniejsz tę wartość, aby powiadomienia były wysyłane wcześniej. Jeśli powiadomienia o nadmiarowym ciśnieniu w pamięci są niepotrzebnie wywoływane, zwiększ tę wartość, aby zmniejszyć wrażliwość urządzenia na hałas. | 70 |
200 |
ro.lmk.psi_complete_stall_ms |
Całkowity próg zablokowania PSI (w milisekundach) do wywołania powiadomień o krytycznym wykorzystaniu pamięci. Jeśli urządzenie otrzymuje powiadomienia o krytycznym poziomie pamięci zbyt późno, zmniejsz tę wartość, aby powiadomienia były wysyłane wcześniej. Jeśli powiadomienia o krytycznym obciążeniu pamięci są niepotrzebnie aktywowane, zwiększ tę wartość, aby zmniejszyć wrażliwość urządzenia na hałas. | 700 |
|
ro.lmk.thrashing_limit |
Maksymalna liczba refaultów zbioru roboczego w procentach z łącznego rozmiaru pamięci podręcznej obsługiwanej przez plik. Wartości większe od tej wartości oznaczają, że system nadmiernie wykorzystuje pamięć podręczną. Jeśli wydajność urządzenia jest ograniczona przez obciążenie pamięci, zmniejsz tę wartość, aby ograniczyć thrashing. Jeśli wydajność urządzenia jest niepotrzebnie obniżana z powodu thrashingu, zwiększ wartość, aby zezwolić na więcej thrashingu. | 100 |
30 |
ro.lmk.thrashing_limit_decay |
Zmniejszenie progu tłoczenia wyrażone jako procent pierwotnego progu służący do obniżenia progu, gdy system nie wraca do normy nawet po zabiciu. Jeśli ciągłe stosowanie funkcji thrashing powoduje niepotrzebne zabijanie procesów, zmniejsz tę wartość. Jeśli reakcja na ciągłe uderzenia po zabiciu jest zbyt wolna, zwiększ wartość. | 10 |
50 |
ro.lmk.swap_util_max |
Maksymalna ilość pamięci wymiennej jako odsetek łącznej pamięci wymiennej. Gdy ilość pamięci wymiennej przekroczy ten limit, oznacza to, że system wykorzystał większość pamięci wymiennej i nadal jest obciążony.
Może się to zdarzyć, gdy alokacje, których nie można zamienić, powodują wzrost zapotrzebowania na pamięć, którego nie można zmniejszyć przez zamianę, ponieważ większość pamięci, którą można zamienić, jest już zamieniona. Wartość domyślna to 100, co w efekcie wyłącza to sprawdzanie. Jeśli wydajność urządzenia jest niska podczas
nacisku pamięci, gdy wykorzystanie podmiany jest wysokie, a poziom wolnej podmiany
nie spada do ro.lmk.swap_free_low_percentage , zmniejsz
tę wartość, aby ograniczyć wykorzystanie podmiany. |
100 |
100 |
W ramach nowej strategii zabijania działają też te stare pokrętła.
Właściwość | Użyj | Domyślny | |
---|---|---|---|
Wysoka wydajność | Mała ilość pamięci RAM | ||
ro.lmk.swap_free_low_percentage |
Poziom bezpłatnego przełączania jako odsetek całkowitego miejsca na wymianę. Funkcja `lmkd` używa tej wartości jako progu, po przekroczeniu którego system uznaje, że brakuje mu miejsca na swapie. Jeśli `lmkd` zabija, gdy jest zbyt dużo miejsca na wymianie, zmniejsz odsetek. Jeśli zabijanie przez `lmkd` następuje zbyt późno, co pozwala na zabijanie przez OOM, zwiększ ten odsetek. | 20 |
10 |
ro.lmk.debug |
Spowoduje to włączenie dzienników debugowania `lmkd`. Włącz debugowanie podczas strojenia. | false |