Demon zabójcy małej pamięci

Proces demona niskiego poziomu pamięci w systemie Android ( lmkd ) monitoruje stan pamięci działającego systemu Android i reaguje na wysokie zużycie pamięci, zabijając najmniej istotne procesy, aby utrzymać działanie systemu na akceptowalnym poziomie.

O presji pamięci

System Android działający równolegle z wieloma procesami może napotkać sytuacje, w których pamięć systemowa jest wyczerpana, a procesy wymagające większej ilości pamięci doświadczają zauważalnych opóźnień. Ciśnienie pamięci , stan, w którym systemowi brakuje pamięci, wymaga od systemu Android zwolnienia pamięci (w celu złagodzenia presji) przez ograniczanie lub zabijanie nieistotnych procesów, żądanie zwolnienia niekrytycznych zasobów z pamięci podręcznej i tak dalej.

Historycznie rzecz biorąc, Android monitorował ciśnienie pamięci systemowej za pomocą wbudowanego w jądro sterownika niskiego poziomu pamięci (LMK), sztywnego mechanizmu, który zależy od wartości zakodowanych na stałe. Począwszy od jądra 4.12, sterownik LMK jest usuwany z jądra nadrzędnego, a przestrzeń użytkownika lmkd wykonuje zadania monitorowania pamięci i zabijania procesów.

Informacje o stajni ciśnieniowej

Android 10 i nowsze obsługują nowy tryb lmkd , który używa monitorów informacji o utknięciu ciśnienia jądra (PSI) do wykrywania ciśnienia w pamięci. Zestaw poprawek PSI w jądrze nadrzędnym (przeniesiony do jąder 4.9 i 4.14) mierzy ilość czasu, o jaką zadania są opóźnione w wyniku braku pamięci. Ponieważ te opóźnienia bezpośrednio wpływają na wrażenia użytkownika, stanowią wygodną metrykę do określania wagi presji pamięci. Nadrzędne jądro zawiera również monitory PSI, które umożliwiają uprzywilejowanym procesom w przestrzeni użytkownika (takim jak lmkd ) określanie progów dla tych opóźnień i subskrybowanie zdarzeń z jądra w przypadku przekroczenia progu.

Monitory PSI a sygnały vmpressure

Ponieważ sygnały vmpressure (generowane przez jądro do wykrywania obciążenia pamięci i używane przez lmkd ) często zawierają wiele fałszywych alarmów, lmkd musi przeprowadzić filtrowanie, aby określić, czy pamięć jest pod rzeczywistym obciążeniem. Powoduje to niepotrzebne lmkd i użycie dodatkowych zasobów obliczeniowych. Korzystanie z monitorów PSI zapewnia dokładniejsze wykrywanie nacisku pamięci i minimalizuje koszty filtrowania.

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 , dzięki czemu monitory PSI są domyślnym mechanizmem wykrywania nacisku pamięci dla lmkd . Ponieważ monitory PSI wymagają obsługi jądra, jądro musi zawierać poprawki backportu PSI i być skompilowane z włączoną obsługą PSI ( CONFIG_PSI=y ).

Wady wbudowanego sterownika LMK

Android wycofuje sterownik LMK z powodu wielu problemów, w tym:

  • Urządzenia o małej ilości pamięci RAM musiały być agresywnie dostrajane, a nawet wtedy działałyby słabo w przypadku obciążeń z dużym, aktywnym buforem stron opartym na plikach. Słaba wydajność spowodowała thrashowanie i brak zabójstw.
  • Sterownik jądra LMK opierał się na limitach wolnej pamięci, bez skalowania opartego na obciążeniu pamięci.
  • Ze względu na sztywność konstrukcji partnerzy często dostosowywali sterownik tak, aby działał na ich urządzeniach.
  • Sterownik LMK podłączył się do interfejsu API zmniejszania slabów, który nie został zaprojektowany do ciężkich operacji, takich jak wyszukiwanie celów i ich zabijanie, co spowolniło proces vmscan .

Przestrzeń użytkownika

Przestrzeń użytkownika lmkd implementuje tę samą funkcjonalność co sterownik wbudowany w jądro, ale wykorzystuje istniejące mechanizmy jądra do wykrywania i szacowania obciążenia pamięci. Takie mechanizmy obejmują używanie generowanych przez jądro zdarzeń vmpressure lub monitorów informacji o zatrzymaniu ciśnienia (PSI) w celu otrzymywania powiadomień o poziomach ciśnienia pamięci oraz używanie funkcji pamięci cgroup w celu ograniczenia zasobów pamięci przydzielonych każdemu procesowi na podstawie ważności procesu.

Korzystanie z lmkd w przestrzeni użytkownika w systemie Android 10

W systemie Android 9 i nowszych lmkd w przestrzeni użytkownika aktywuje się, jeśli sterownik LMK w jądrze nie zostanie wykryty. Ponieważ userspace lmkd wymaga obsługi jądra dla cgroups pamięci, jądro musi być skompilowane z następującymi ustawieniami konfiguracyjnymi:

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

Strategie zabijania

lmkd obsługuje strategie kill oparte na zdarzeniach vmpressure lub monitorach PSI, ich ważności i innych wskazówkach, takich jak wykorzystanie wymiany. Strategie zabijania różnią się między urządzeniami o małej ilości pamięci i urządzeniami o wysokiej wydajności:

  • Na urządzeniach o małej ilości pamięci system powinien tolerować wyższe zużycie pamięci jako normalny tryb działania.
  • Na urządzeniach o wysokiej wydajności ciśnienie pamięci powinno być postrzegane jako sytuacja nienormalna i naprawione, zanim wpłynie na ogólną wydajność.

Strategię zabijania można skonfigurować za pomocą właściwości ro.config.low_ram . Aby uzyskać szczegółowe informacje, zobacz Konfiguracja z niskim suwakiem .

lmkd w przestrzeni użytkownika obsługuje również tryb starszej wersji, w którym podejmuje decyzje o zabiciu przy użyciu 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 starszej wersji, ustaw właściwość ro.lmk.use_minfree_levels na true .

Konfiguracja lmkd

Skonfiguruj lmkd dla określonego urządzenia, korzystając z następujących właściwości.

Nieruchomość Posługiwać się Domyślna
ro.config.low_ram Określ, czy urządzenie jest urządzeniem o małej ilości pamięci RAM, czy o wysokiej wydajności. false
ro.lmk.use_psi Użyj monitorów PSI (zamiast zdarzeń vmpressure ). true
ro.lmk.use_minfree_levels Użyj progów wolnej pamięci i pamięci podręcznej plików do podejmowania decyzji o zakończeniu procesu (czyli dopasuj funkcjonalność wbudowanego w jądro sterownika LMK). false
ro.lmk.low Minimalny wynik oom_adj dla procesów kwalifikujących się do zabicia na niskim poziomie vmpressure . 1001
(wyłączony)
ro.lmk.medium Minimalny wynik oom_adj dla procesów kwalifikujących się do zabicia na średnim poziomie vmpressure . 800
(usługi z pamięci podręcznej lub nieistotne)
ro.lmk.critical Minimalny wynik oom_adj dla procesów kwalifikujących się do zabicia na krytycznym poziomie vmpressure . 0
(dowolny proces)
ro.lmk.critical_upgrade Włącz aktualizację do poziomu krytycznego. false
ro.lmk.upgrade_pressure Maksymalna wartość mem_pressure , przy której poziom jest aktualizowany, ponieważ system za bardzo się zmienia. 100
(wyłączony)
ro.lmk.downgrade_pressure Minimalna wartość mem_pressure , przy której zdarzenie vmpressure jest ignorowane, ponieważ wciąż dostępna jest wystarczająca ilość wolnej pamięci. 100
(wyłączony)
ro.lmk.kill_heaviest_task Zabij najcięższe kwalifikujące się zadanie (najlepsza decyzja) w porównaniu z dowolnym kwalifikującym się zadaniem (szybka decyzja). true
ro.lmk.kill_timeout_ms Czas trwania w milisekundach po zabiciu, gdy nie zostanie wykonane żadne dodatkowe zabójstwo. 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ę zabijania. Strategia zabijania wykorzystuje mechanizm PSI do wykrywania nacisku pamięci wprowadzony w systemie Android 10. lmkd w systemie Android 11 uwzględnia poziomy wykorzystania zasobów pamięci i thrashing, aby zapobiec głodowi pamięci i pogorszeniu wydajności. Ta strategia zabijania zastępuje poprzednie strategie i może być używana zarówno na urządzeniach o wysokiej wydajności, jak io małej ilości pamięci RAM (Android Go).

Wymagania jądra

W przypadku urządzeń z systemem Android 11 lmkd wymaga następujących funkcji jądra:

  • Dołącz łatki PSI i włącz PSI (backporty dostępne w popularnych jądrach Androida 4.9, 4.14 i 4.19).
  • Dołącz poprawki obsługujące PIDFD (backporty dostępne w popularnych jądrach Androida 4.9, 4.14 i 4.19).
  • W przypadku urządzeń z małą ilością pamięci RAM należy uwzględnić cgroups pamięci.

Jądro musi być skompilowane z następującymi ustawieniami konfiguracyjnymi:

CONFIG_PSI=y

Konfiguracja lmkd w Androidzie 11

Strategia zabijania pamięci w systemie Android 11 obsługuje pokrętła strojenia 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.

Nieruchomość Posługiwać się Domyślna
Wysoka wydajność Niska pamięć RAM
ro.lmk.psi_partial_stall_ms Próg częściowego utknięcia PSI w milisekundach do wyzwalania powiadomienia o małej ilości pamięci. Jeśli urządzenie zbyt późno otrzymuje powiadomienia o obciążeniu pamięci, zmniejsz tę wartość, aby wyzwolić wcześniejsze powiadomienia. Jeśli powiadomienia o obciążeniu pamięci są uruchamiane niepotrzebnie, zwiększ tę wartość, aby urządzenie było mniej wrażliwe na hałas. 70 200
ro.lmk.psi_complete_stall_ms Całkowity próg utknięcia PSI (w milisekundach) do wyzwalania krytycznych powiadomień dotyczących pamięci. Jeśli urządzenie zbyt późno otrzymuje powiadomienia o krytycznym obciążeniu pamięci, zmniejsz tę wartość, aby wyzwolić wcześniejsze powiadomienia. Jeśli powiadomienia o krytycznym ciśnieniu pamięci są wyzwalane niepotrzebnie, zwiększ tę wartość, aby urządzenie było mniej wrażliwe na hałas. 700
ro.lmk.thrashing_limit Maksymalna liczba błędów zestawu roboczego jako procent całkowitego rozmiaru pamięci podręcznej stron z plikami. Błędy zestawu roboczego powyżej tej wartości oznaczają, że system jest uważany za przeczyszczający swoją pamięć podręczną stron. Jeśli wydajność urządzenia ma wpływ na obciążenie pamięci, zmniejsz wartość, aby ograniczyć thrashing. Jeśli wydajność urządzenia zostanie niepotrzebnie obniżona z powodu thrashingu, zwiększ wartość, aby umożliwić więcej thrashingu. 100 30
ro.lmk.thrashing_limit_decay Zanik progu thrashowania wyrażony jako procent pierwotnego progu używany do obniżenia progu, gdy system nie działa, nawet po zabiciu. Jeśli ciągłe thrashowanie powoduje niepotrzebne zabójstwa, zmniejsz wartość. Jeśli reakcja na ciągłe thrashowanie po zabójstwie jest zbyt wolna, zwiększ wartość. 10 50
ro.lmk.swap_util_max Maksymalna ilość wymienianej pamięci jako procent całkowitej ilości wymienianej pamięci. Gdy wymieniana pamięć przekroczy ten limit, oznacza to, że system zamienił większość swojej wymiennej pamięci i nadal jest pod presją. Może się to zdarzyć, gdy alokacje niewymienialne generują ciśnienie pamięci, którego nie można złagodzić przez zamianę, ponieważ większość pamięci wymiennej jest już zamieniona. Wartość domyślna to 100, co skutecznie wyłącza to sprawdzenie. Jeśli wydajność urządzenia ma wpływ na ciśnienie pamięci, gdy wykorzystanie wymiany jest wysokie, a poziom bezpłatnej wymiany nie spada do ro.lmk.swap_free_low_percentage , zmniejsz wartość, aby ograniczyć wykorzystanie wymiany. 100 100

Poniższe stare pokrętła strojenia działają również z nową strategią zabijania.

Nieruchomość Posługiwać się Domyślna
Wysoka wydajność Niska pamięć RAM
ro.lmk.swap_free_low_percentage Poziom wolnej wymiany jako procent całkowitej przestrzeni wymiany. `lmkd` używa tej wartości jako progu, kiedy należy uznać system za brak przestrzeni wymiany. Jeśli `lmkd` zabije, gdy w swapie jest za dużo miejsca, zmniejsz procent. Jeśli zabójstwa `lmkd` zdarzają się zbyt późno, co pozwala na zabijanie przez OOM, zwiększ procent. 20 10
ro.lmk.debug Włącza to dzienniki debugowania `lmkd`. Włącz debugowanie podczas strojenia. false