Demon Low Memory Killer

Proces demona Androida, który zabija procesy przy niskim poziomie pamięci (lmkd), monitoruje stan pamięci działającego systemu Android i reaguje na wysokie obciążenie pamięci, zabijając najmniej istotne procesy, aby utrzymać wydajność systemu na akceptowalnym poziomie.

Informacje o obciążeniu pamięci

System Android, w którym działa równolegle wiele procesów, może napotkać sytuacje, w których pamięć systemowa jest wyczerpana, a procesy wymagające więcej pamięci doświadczają zauważalnych opóźnień. Niedobór pamięci to stan, w którym system ma za mało pamięci. Wymaga on od Androida zwolnienia pamięci (aby zmniejszyć niedobór) przez ograniczanie lub zamykanie nieważnych procesów, proszenie procesów o zwolnienie niekrytycznych zasobów w pamięci podręcznej itp.

W przeszłości Android monitorował obciążenie pamięci systemowej za pomocą sterownika LMK (low memory killer) w jądrze, który był sztywnym mechanizmem zależnym od zakodowanych na stałe wartości. Od wersji jądra 4.12 sterownik LMK został usunięty z jądra upstream, a przestrzeń użytkownika lmkd wykonuje zadania monitorowania pamięci i zamykania procesów.

Informacje o przeciągnięciu

Android 10 i nowsze obsługują nowy tryb lmkd, który do wykrywania obciążenia pamięci wykorzystuje monitory informacji o obciążeniu jądra (PSI). Zestaw poprawek PSI w jądrze upstream (przeniesiony do jąder 4.9 i 4.14) mierzy czas opóźnienia zadań z powodu niedoboru pamięci. Opóźnienia te bezpośrednio wpływają na wrażenia użytkowników, dlatego są wygodnym wskaźnikiem do określania stopnia obciążenia pamięci. Jądro upstream zawiera też monitory PSI, które umożliwiają uprzywilejowanym procesom przestrzeni użytkownika (np. lmkd) określanie progów tych opóźnień i subskrybowanie zdarzeń z jądra, gdy próg zostanie przekroczony.

Monitorowanie PSI a sygnały vmpressure

Sygnały vmpressure (generowane przez jądro na potrzeby wykrywania niskiego poziomu pamięci i używane przez lmkd) często zawierają liczne fałszywe alarmy, dlatego lmkd musi przeprowadzać filtrowanie, aby określić, czy pamięć jest rzeczywiście obciążona. Powoduje to niepotrzebne lmkd wybudzenia i wykorzystanie dodatkowych zasobów obliczeniowych. Korzystanie z PSI pozwala dokładniej wykrywać obciążenie pamięci i minimalizować narzut związany z filtrowaniem.

Korzystanie z monitorów PSI

Aby używać monitorów PSI zamiast zdarzeń vmpressure, skonfiguruj właściwość ro.lmk.use_psi. Domyślna wartość to true, co sprawia, że monitory PSI są domyślnym mechanizmem wykrywania obciążenia pamięci w przypadku lmkd. Ponieważ monitory PSI wymagają obsługi jądra, musi ono zawierać poprawki PSI i być skompilowane z włączoną obsługą PSI (CONFIG_PSI=y).

Wady sterownika LMK w jądrze

Android wycofuje sterownik LMK z powodu wielu problemów, m.in.:

  • Urządzenia z niewielką ilością pamięci RAM musiały być agresywnie dostrajane, a nawet wtedy działały słabo w przypadku zadań z dużą ilością aktywnych stron w pamięci podręcznej plików. Słaba wydajność spowodowała thrashing i brak zabójstw.
  • Sterownik jądra LMK opierał się na limitach wolnej pamięci i nie skalował się 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 zmniejszania rozmiaru bloku, który nie został zaprojektowany do wykonywania złożonych operacji, takich jak wyszukiwanie celów i ich zamykanie, co spowalniało proces vmscan.

Userspace lmkd

Przestrzeń użytkownika lmkd ma taką samą funkcjonalność jak sterownik w jądrze, ale do wykrywania i szacowania obciążenia pamięci używa istniejących mechanizmów jądra. Takie mechanizmy obejmują używanie zdarzeń vmpressure generowanych przez jądro lub monitorów informacji o zatrzymaniu z powodu obciążenia (PSI) w celu otrzymywania powiadomień o poziomach obciążenia pamięci oraz używanie funkcji grupy pamięci do ograniczania zasobów pamięci przydzielanych 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 wersjach przestrzeń użytkownika lmkd jest aktywowana, jeśli nie wykryto sterownika LMK w jądrze. Ponieważ przestrzeń użytkownika lmkd wymaga obsługi przez jądro grup pamięci, jądro musi być skompilowane z tymi ustawieniami konfiguracji:

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

Strategie wycofywania

Przestrzeń użytkownikalmkd obsługuje strategie zamykania procesów oparte na vmpressure zdarzeniach lub monitorach PSI, ich ważności i innych wskazówkach, takich jak wykorzystanie pamięci wymiany. Strategie zamykania różnią się w przypadku urządzeń o małej i dużej ilości pamięci:

  • Na urządzeniach z małą ilością pamięci system powinien tolerować większe wykorzystanie pamięci jako normalny tryb działania.
  • Na urządzeniach o wysokiej wydajności wykorzystanie pamięci powinno być traktowane jako sytuacja nietypowa i należy je rozwiązać, zanim wpłynie na ogólną wydajność.

Strategię zamykania możesz skonfigurować za pomocą właściwości ro.config.low_ram.

Przestrzeń użytkownika lmkd obsługuje też tryb starszego typu, w którym podejmuje decyzje o zakończeniu procesu, korzystając z tych samych strategii co sterownik LMK w jądrze (czyli progi wolnej pamięci i pamięci podręcznej plików). Aby włączyć tryb starszy, ustaw właściwość ro.lmk.use_minfree_levels na true.

Konfigurowanie usługi lmkd

Skonfiguruj lmkd na konkretnym urządzeniu, korzystając z tych właściwości.

Właściwość Użyj Domyślny
ro.config.low_ram Określ, czy urządzenie ma mało pamięci RAM, czy jest urządzeniem 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 pamięci podręcznej plików do podejmowania decyzji o zakończeniu procesu (czyli dopasuj funkcjonalność sterownika LMK w jądrze). false
ro.lmk.low Minimalny wynik oom_adj dla procesów, które można zakończyć na niskim poziomie vmpressure. 1001
(wyłączony)
ro.lmk.medium Minimalny wynik oom_adj dla procesów, które można zakończyć na średnim poziomie vmpressure. 800
(usługi przechowywane w pamięci podręcznej lub nieistotne)
ro.lmk.critical Minimalny wynik oom_adj dla procesów, które można zakończyć na krytycznym poziomie vmpressure. 0
(dowolny proces)
ro.lmk.critical_upgrade Włącz uaktualnienie do poziomu krytycznego. false
ro.lmk.upgrade_pressure Maksymalna wartość mem_pressure, przy której poziom jest podnoszony, ponieważ system zbyt często wymienia dane. 100
(wyłączony)
ro.lmk.downgrade_pressure Minimalna wartość mem_pressure, przy której zdarzenie vmpressure jest ignorowane, ponieważ jest jeszcze wystarczająco dużo wolnej pamięci. 100
(wyłączony)
ro.lmk.kill_heaviest_task Zakończ najcięższe kwalifikujące się zadanie (najlepsza decyzja) zamiast dowolnego kwalifikującego się zadania (szybka decyzja). false
ro.lmk.kill_timeout_ms Czas w milisekundach po zabiciu, po którym nie nastąpi kolejne zabicie. 0
(wyłączony)
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

Przestrzeń użytkownika lmkd w Androidzie 11

Android 11 ulepsza lmkd, wprowadzając nową strategię zamykania aplikacji. Strategia zamykania korzysta z mechanizmu PSI do wykrywania presji pamięci wprowadzonego w Androidzie 10. lmkdW Androidzie 11 uwzględniane są poziomy wykorzystania pamięci i przepełnienie, aby zapobiegać niedoborom pamięci i spadkom wydajności. Ta strategia zamykania 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:

  • Zawiera poprawki PSI i włącza PSI (wersje wsteczne dostępne w wersjach 4.9, 4.14 i 4.19 wspólnych jąder Androida).
  • Zawiera poprawki obsługi PIDFD (wersje wsteczne dostępne w wersjach 4.9, 4.14 i 4.19 wspólnych jąder Androida).
  • W przypadku urządzeń z małą ilością pamięci RAM uwzględnij grupy kontrolne pamięci.

Jądro musi być skompilowane z tymi ustawieniami konfiguracji:

CONFIG_PSI=y

Konfigurowanie lmkd na Androidzie 11

Strategia zwalniania pamięci w Androidzie 11 obsługuje parametry 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 zatrzymania PSI w milisekundach, który powoduje wyświetlenie powiadomienia o niskim poziomie pamięci. Jeśli urządzenie otrzymuje powiadomienia o niskim poziomie pamięci zbyt późno, zmniejsz tę wartość, aby powiadomienia były wysyłane wcześniej. Jeśli powiadomienia o niskim poziomie pamięci są wywoływane niepotrzebnie, zwiększ tę wartość, aby zmniejszyć czułość urządzenia na szum. 70 200
ro.lmk.psi_complete_stall_ms Pełny próg zatrzymania PSI w milisekundach, który powoduje wywołanie krytycznych powiadomień o 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ą wywoływane niepotrzebnie, zwiększ tę wartość, aby zmniejszyć wrażliwość urządzenia na szum. 700
ro.lmk.thrashing_limit Maksymalna liczba ponownych błędów w zestawie roboczym jako odsetek łącznego rozmiaru pamięci podręcznej stron z plikami. Ponowne błędy w zestawie roboczym powyżej tej wartości oznaczają, że system jest uznawany za nadmiernie obciążony pamięcią podręczną stron. Jeśli wydajność urządzenia jest obniżona z powodu obciążenia pamięci, zmniejsz tę wartość, aby ograniczyć thrashing. Jeśli wydajność urządzenia jest niepotrzebnie obniżana z powodu nadmiernego obciążenia, zwiększ tę wartość, aby umożliwić większe obciążenie. 100 30
ro.lmk.thrashing_limit_decay Próg gwałtownego spadku wydajności wyrażony jako procent pierwotnego progu używanego do obniżania progu, gdy system nie odzyskuje wydajności nawet po zakończeniu procesu. Jeśli ciągłe thrashing powoduje niepotrzebne zakończenia procesów, zmniejsz tę wartość. Jeśli odpowiedź na ciągłe thrashing po zakończeniu procesu jest zbyt wolna, zwiększ tę wartość. 10 50
ro.lmk.swap_util_max Maksymalna ilość pamięci wymiany jako procent łącznej pamięci wymiany. Gdy pamięć wymiany przekroczy ten limit, oznacza to, że system wymienił większość pamięci, którą można wymieniać, i nadal jest pod presją. Może się to zdarzyć, gdy alokacje, których nie można zamienić, powodują nadmierne obciążenie pamięci, 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 praktyce wyłącza to sprawdzanie. Jeśli wydajność urządzenia jest obniżona z powodu dużego obciążenia pamięci, a wykorzystanie pamięci wymiany jest wysokie i nie spada do poziomu ro.lmk.swap_free_low_percentage, zmniejsz wartość, aby ograniczyć wykorzystanie pamięci wymiany. 100 100

Z nową strategią zamykania działają też te stare opcje dostrajania:

Właściwość Użyj Domyślny
Wysoka wydajność Mała ilość pamięci RAM
ro.lmk.swap_free_low_percentage Poziom wolnej przestrzeni wymiany jako odsetek całkowitej przestrzeni wymiany. `lmkd` używa tej wartości jako progu, po przekroczeniu którego system jest uznawany za mający za mało miejsca na wymianę. Jeśli `lmkd` zabija procesy, gdy w pamięci wymiany jest zbyt dużo miejsca, zmniejsz ten odsetek. Jeśli procesy zabijane przez `lmkd` są zamykane zbyt późno, co powoduje zabijanie procesów z powodu braku pamięci, zwiększ wartość procentową. 20 10
ro.lmk.debug Włącza to dzienniki debugowania `lmkd`. Włącz debugowanie podczas dostrajania. false