Demon zabijający mało pamięci

Demon (lmkd) Androida do zabijania procesów przy niskim poziomie pamięci monitoruje stan pamięci działającego systemu Androida i reaguje na wysokie obciążenie pamięci, zabijając procesy o najmniejszym znaczeniu, aby zachować akceptowalne osiągiwanie przez system.

Informacje o obciążeniu pamięci

W przypadku systemu Android uruchamianego równolegle mogą wystąpić sytuacje, gdy pamięć systemu się wyczerpie, a procesy wymagające więcej pamięci będą zauważalne opóźnienia. Wykorzystanie pamięci, czyli stan, w którym system ma za mało pamięci, wymaga od Androida zwolnienia pamięci (aby zmniejszyć presję) przez ograniczanie lub zatrzymywanie nieistotnych procesów, wysyłanie żądań do procesów zwalniania niekrytycznych zasobów zapisanych w pamięci podręcznej itp.

Wcześniej Android monitorował obciążenie pamięci systemowej za pomocą sterownika LMK (Low Memory Killer) działającego w rdzeniu. Jest to sztywny mechanizm, który zależy od zakodowanych na stałe wartości. 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 budynku ciśnieniowym

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 (przeniesiony do wersji 4.9 i 4.14) mierzy czas opóźnienia zadań spowodowany brakiem pamięci. Opóźnienia te bezpośrednio wpływają na wygodę użytkowników, dlatego są one wygodnym wskaźnikiem poziomu wykorzystania 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 kernela, gdy zostanie przekroczona wartość progowa.

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łszywie pozytywnych wyników, 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 nakłady związane z filtrowaniem.

Korzystanie z monitorów PSI

Aby używać monitorów PSI zamiast zdarzeń vmpressure, skonfiguruj właściwość ro.lmk.use_psi. Wartość domyślna to true, co oznacza, że PSI monitoruje domyślny mechanizm wykrywania wykorzystania pamięci w lmkd. Monitory PSI wymagają obsługi przez jądro, dlatego jądro musi zawierać łaty do wstecznego przenoszenia PSI i być skompilowane z włączoną obsługą PSI (CONFIG_PSI=y).

Wady sterownika LMK umieszczonego w jądrze

Android wycofuje sterownik LMK z powodu szeregu problemów, takich jak:

  • Urządzenia z małą ilością pamięci RAM wymagały agresywnego dostosowania, a nawet wtedy pracowały słabo w przypadku zadań 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ść konstrukcji partnerzy często dostosowali przetwornik tak, aby działał na ich urządzeniach.
  • Sterownik LMK był podłączony do interfejsu API Shrinker, który nie został zaprojektowany z myślą o intensywnych operacjach, takich jak wyszukiwanie i 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 zatrzymaniu z powodu braku zasobów (PSI), aby otrzymywać powiadomienia o poziomie zasobów pamięci, oraz korzystanie z funkcji cgroup pamięci, aby ograniczyć zasoby pamięci przydzielone poszczególnym procesom na podstawie ich 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, należy skompilować jądro z tymi ustawieniami konfiguracji:

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

Strategie zabijania

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ć wyższe wykorzystanie pamięci 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ę wycofania możesz skonfigurować za pomocą usługi ro.config.low_ram. Więcej informacji znajdziesz w sekcji Konfiguracja z małą ilością pamięci 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 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 procesów (czyli dopasowanych do funkcjonalności sterownika LMK znajdującego się w jądrze). false
ro.lmk.low Minimalny wynik oom_adj procesów kwalifikujących się do zakończenia na niskim poziomie vmpressure. 1001
(wyłączony)
ro.lmk.medium Minimalny wynik oom_adj procesów kwalifikujących się do zakończenia na średnim poziomie vmpressure. 800
(usługi w pamięci podręcznej lub usługi niepotrzebne)
ro.lmk.critical Minimalny wynik oom_adj procesów, które mogą zostać przerwane 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 innym 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 wykorzystuje obecny w Androidzie 10 mechanizm PSI do wykrywania wykorzystania pamięci. lmkd w Androidzie 11 uwzględnia poziomy wykorzystania zasobów pamięci i szyfrowanie, co zapobiega wyczerpaniu się pamięci i 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 jądra systemu

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).
  • Uwzględnij poprawki obsługujące PIDFD (porty dostępne w typowych jądrach Androida 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 LDAP 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 małą ilością pamięci RAM.

Właściwość Użyj Domyślny
Wysoka wydajność Mało 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 nadmiarze pamięci zbyt późno, zmniejsz tę wartość, aby powiadomienia były wysyłane wcześniej. Jeśli powiadomienia o nadmiarowym ciśnieniu są niepotrzebnie aktywowane, 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 uważa, że jego pamięć podręczna jest przeciążona. Jeśli wydajność urządzenia jest ograniczona z powodu obciążenia pamięci, zmniejsz tę wartość, aby ograniczyć thrashing. Jeśli wydajność urządzenia jest niepotrzebnie ograniczana z powodu thrashingu, zwiększ wartość, aby umożliwić więcej thrashingu. 100 30
ro.lmk.thrashing_limit_decay Spadek progu rzutów wyrażony jako procent pierwotnego progu użytego do obniżenia progu, gdy system nie wróci do zdrowia 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 twarde uderzenia po zabiciu jest zbyt wolna, zwiększ wartość. 10 50
ro.lmk.swap_util_max Maksymalna ilość pamięci podręcznej jako procent łącznej pamięci, którą można zamienić. Gdy ilość pamięci wymiennej przekroczy ten limit, oznacza to, że system przełączył 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 presji pamięci, a wykorzystanie swapa jest wysokie i poziom wolnego swapa nie spada do ro.lmk.swap_free_low_percentage, zmniejsz tę wartość, aby ograniczyć wykorzystanie swapa. 100 100

W przypadku nowej strategii wygaszania działają też te stare ustawienia.

Właściwość Użyj Domyślny
Wysoka wydajność Mała ilość pamięci RAM
ro.lmk.swap_free_low_percentage Poziom wolnego miejsca na wymianę jako procent 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 dysku. Jeśli parametr „lmkd” zakończy działanie z powodu zbyt dużej ilości miejsca w wymianie, zmniejsz tę wartość procentową. 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 logów debugowania „lmkd”. Włącz debugowanie podczas dostrajania. false