Platforma Android działa na założeniu, że wolna pamięć to pamięć zmarnowana. Stara się ona zawsze wykorzystywać całą dostępną pamięć. Na przykład system przechowuje aplikacje w pamięci po ich zamknięciu, aby użytkownik mógł szybko do nich wrócić. Z tego powodu urządzenia z Androidem często działają z bardzo małą ilością wolnej pamięci. Zarządzanie pamięcią jest niezbędne do prawidłowego przydzielania pamięci między ważne procesy systemowe i wiele aplikacji użytkownika.
Na tej stronie omówimy podstawy przydzielania pamięci przez Androida na potrzeby systemu i aplikacji użytkownika. Wyjaśnimy też, jak system operacyjny reaguje na sytuacje, w których jest mało pamięci.
Rodzaje pamięci
Urządzenia z Androidem mają 3 rodzaje pamięci: RAM, zRAM i pamięć na dane. Pamiętaj, że zarówno procesor, jak i GPU mają dostęp do tej samej pamięci RAM.
Rysunek 1. Rodzaje pamięci – RAM, zRAM i pamięć na dane
RAM to najszybszy rodzaj pamięci, ale zwykle ma ograniczoną pojemność. Najwięcej pamięci RAM mają urządzenia z wyższej półki.
zRAM to partycja pamięci RAM używana jako przestrzeń wymiany. Wszystko jest kompresowane, gdy jest umieszczane w zRAM, a następnie dekompresowane, gdy jest z niej kopiowane. Ta część pamięci RAM zwiększa lub zmniejsza swój rozmiar w miarę przenoszenia stron do zRAM lub z niej. Producenci urządzeń mogą ustawić maksymalny rozmiar.
Pamięć na dane zawiera wszystkie trwałe dane, takie jak system plików i dołączony kod obiektowy wszystkich aplikacji, bibliotek i platformy. Pamięć na dane ma znacznie większą pojemność niż pozostałe 2 rodzaje pamięci. W Androidzie pamięć na dane nie jest używana jako przestrzeń wymiany, jak w innych implementacjach systemu Linux, ponieważ częste zapisywanie może powodować zużycie tej pamięci i skrócić żywotność nośnika danych.
Strony pamięci
Pamięć RAM jest podzielona na strony. Zwykle każda strona ma 4 KB pamięci.
Strony są uważane za wolne lub używane. Wolne strony to nieużywana pamięć RAM. Używane strony to pamięć RAM, z której aktywnie korzysta system. Są one podzielone na te kategorie:
- Pamięć podręczna: pamięć obsługiwana przez plik w pamięci na dane (np. kod lub pliki mapowane w pamięci). Istnieją 2 rodzaje pamięci podręcznej:
- Prywatna: należy do 1 procesu i nie jest udostępniana.
- Czysta: niezmodyfikowana kopia pliku w pamięci na dane, którą można usunąć za pomocą
kswapd, aby zwiększyć ilość wolnej pamięci. - Zanieczyszczona: zmodyfikowana kopia pliku w pamięci na dane; można ją przenieść do zRAM lub skompresować w zRAM za pomocą
kswapd, aby zwiększyć ilość wolnej pamięci.
- Czysta: niezmodyfikowana kopia pliku w pamięci na dane, którą można usunąć za pomocą
- Udostępniona: używana przez wiele procesów.
- Czysta: niezmodyfikowana kopia pliku w pamięci na dane, którą można usunąć za pomocą
kswapd, aby zwiększyć ilość wolnej pamięci. - Zanieczyszczona: zmodyfikowana kopia pliku w pamięci na dane; umożliwia zapisywanie zmian z powrotem do pliku w pamięci na dane, aby zwiększyć ilość wolnej pamięci za pomocą
lub jawnie za pomocą
kswapdmsync()lubmunmap()
- Czysta: niezmodyfikowana kopia pliku w pamięci na dane, którą można usunąć za pomocą
- Prywatna: należy do 1 procesu i nie jest udostępniana.
- Anonimowa: pamięć nie obsługiwana przez plik w pamięci na dane (np.
przydzielona przez
mmap()z ustawioną flagąMAP_ANONYMOUS)- Zmodyfikowana: można ją przenieść do zRAM lub skompresować w zRAM za pomocą
kswapd, aby zwiększyć ilość wolnej pamięci.
- Zmodyfikowana: można ją przenieść do zRAM lub skompresować w zRAM za pomocą
Proporcje wolnych i używanych stron zmieniają się w czasie, ponieważ system aktywnie zarządza pamięcią RAM. Koncepcje przedstawione w tej sekcji są kluczowe w zarządzaniu sytuacjami, w których jest mało pamięci. W następnej sekcji tego dokumentu wyjaśnimy je bardziej szczegółowo.
Zarządzanie małą ilością pamięci
Android ma 2 główne mechanizmy radzenia sobie z sytuacjami, w których jest mało pamięci: demona wymiany jądra i mechanizm zabijania procesów przy małej ilości pamięci.
Demon wymiany jądra
Demon wymiany jądra (kswapd) jest częścią jądra systemu Linux i przekształca używaną pamięć w wolną. Demon staje się aktywny, gdy na urządzeniu zaczyna brakować wolnej pamięci. Jądro systemu Linux utrzymuje niskie i wysokie progi wolnej pamięci.
Gdy ilość wolnej pamięci spadnie poniżej niskiego progu, kswapd zaczyna odzyskiwać pamięć. Gdy ilość wolnej pamięci osiągnie wysoki próg, kswapd przestaje odzyskiwać pamięć.
kswapd może odzyskać czyste strony, usuwając je, ponieważ są one obsługiwane przez pamięć na dane i nie zostały zmodyfikowane. Jeśli proces spróbuje uzyskać dostęp do usuniętej czystej strony, system skopiuje ją z pamięci na dane do pamięci RAM. Ta operacja jest nazywana stronicowaniem na żądanie.
Rysunek 2. Czysta strona obsługiwana przez pamięć na dane została usunięta
kswapd może przenosić zmodyfikowane strony prywatne z pamięci podręcznej i zmodyfikowane strony anonimowe do zRAM, gdzie są kompresowane. Dzięki temu zwalnia się dostępna pamięć RAM (wolne strony). Jeśli proces spróbuje uzyskać dostęp do zmodyfikowanej strony w zRAM, strona zostanie zdekompresowana i przeniesiona z powrotem do pamięci RAM. Jeśli proces powiązany ze skompresowaną stroną zostanie zakończony, strona zostanie usunięta z zRAM.
Jeśli ilość wolnej pamięci spadnie poniżej określonego progu, system zacznie kończyć procesy.
Rysunek 3. Zmodyfikowana strona przeniesiona do zRAM i skompresowana
Mechanizm zabijania procesów przy małej ilości pamięci
W wielu przypadkach kswapd nie może zwolnić wystarczającej ilości pamięci dla systemu. W takim przypadku system używa
onTrimMemory()
, aby powiadomić aplikację, że zaczyna brakować pamięci i że powinna zmniejszyć przydział. Jeśli to nie wystarczy, jądro zacznie kończyć procesy, aby zwolnić pamięć. W tym celu używa mechanizmu zabijania procesów przy małej ilości pamięci (LMK).
Aby zdecydować, który proces zakończyć, LMK używa wyniku "brak pamięci" o nazwie
oom_adj_score
aby określić priorytet uruchomionych procesów. Najpierw kończone są procesy z wysokim wynikiem. Najpierw kończone są aplikacje działające w tle, a na końcu procesy systemowe. W tabeli poniżej wymieniliśmy kategorie wyników LMK od najwyższego do najniższego. Najpierw zostaną zakończone elementy z kategorii o najwyższym wyniku w pierwszym wierszu:
Rysunek 4. Procesy Androida z wysokimi wynikami u góry i niskimi u dołu
Poniżej znajdziesz opisy poszczególnych kategorii w tabeli powyżej:
Aplikacje działające w tle: aplikacje, które były wcześniej uruchomione i nie są obecnie aktywne. LMK najpierw zakończy aplikacje działające w tle, zaczynając od tej z najwyższym wynikiem
oom_adj_score.Poprzednia aplikacja: ostatnio używana aplikacja działająca w tle. Poprzednia aplikacja ma wyższy priorytet (niższy wynik) niż aplikacje działające w tle, ponieważ jest bardziej prawdopodobne, że użytkownik przełączy się na nią niż na jedną z aplikacji działających w tle.
Aplikacja Home: jest to aplikacja uruchamiająca. Jej zakończenie spowoduje zniknięcie tapety.
Usługi: usługi są uruchamiane przez aplikacje i mogą obejmować synchronizację lub przesyłanie do chmury.
Aplikacje widoczne: aplikacje, które nie działają na pierwszym planie, ale są w jakiś sposób widoczne dla użytkownika, np. uruchamiają proces wyszukiwania, który wyświetla mały interfejs, lub odtwarzają muzykę.
Aplikacja działająca na pierwszym planie: aplikacja, która jest obecnie używana. Zakończenie aplikacji działającej na pierwszym planie wygląda jak awaria aplikacji, co może sugerować użytkownikowi, że z urządzeniem coś jest nie tak.
Trwałe (usługi): są to podstawowe usługi urządzenia, takie jak telefonia i Wi-Fi.
System: procesy systemowe. Po zakończeniu tych procesów telefon może się zrestartować.
Natywne: procesy o bardzo niskim poziomie używane przez system (np.
kswapd).
Producenci urządzeń mogą zmienić działanie LMK.
Obliczanie wykorzystania pamięci
Jądro śledzi wszystkie strony pamięci w systemie.
Rysunek 5. Strony używane przez różne procesy
Określając, ile pamięci jest używane przez aplikację, system musi uwzględnić strony udostępnione. Aplikacje, które mają dostęp do tej samej usługi lub biblioteki, będą udostępniać strony pamięci. Na przykład Usługi Google Play i aplikacja do gier mogą udostępniać usługę lokalizacji. Utrudnia to określenie, ile pamięci należy do usługi jako całości, a ile do każdej aplikacji.
Rysunek 6. Strony udostępniane przez 2 aplikacje (środek)
Aby określić wykorzystanie pamięci przez aplikację, można użyć dowolnego z tych wskaźników:
- Rozmiar zestawu rezydentnego (RSS): liczba stron udostępnionych i nieudostępnionych używanych przez aplikację.
- Proporcjonalny rozmiar zestawu (PSS): liczba stron nieudostępnionych używanych przez aplikację i równomierny rozkład stron udostępnionych (np. jeśli 3 procesy udostępniają 3 MB, każdy proces otrzymuje 1 MB w PSS).
- Rozmiar unikalnego zestawu (USS): liczba stron nieudostępnionych używanych przez aplikację (strony udostępnione nie są uwzględniane).
PSS jest przydatny dla systemu operacyjnego, gdy chce on wiedzieć, ile pamięci jest używane przez wszystkie procesy, ponieważ strony nie są liczone wielokrotnie. Obliczenie PSS zajmuje dużo czasu, ponieważ system musi określić, które strony są udostępniane i przez ile procesów. RSS nie rozróżnia stron udostępnionych i nieudostępnionych (co przyspiesza obliczenia) i lepiej nadaje się do śledzenia zmian w alokacji pamięci.
Dodatkowe materiały
- Omówienie zarządzania pamięcią
- Procesy i cykl życia aplikacji
- Wykorzystanie pamięci w Androidzie – prezentacja Google I/O
- Pamięć i gry w Androidzie – prezentacja Google I/O
- Demon zabijania procesów przy małej ilości pamięci w Androidzie
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Czas uruchomienia aplikacji