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 ważnym procesom systemowym i wielu aplikacjom użytkownika.
Na tej stronie znajdziesz podstawowe informacje o tym, jak Android przydziela pamięć systemowi i aplikacjom użytkownika. Wyjaśniamy też, jak system operacyjny reaguje na sytuacje, w których brakuje 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.
Strony pamięci
Pamięć RAM jest podzielona na strony. Zwykle każda strona ma 4 KB pamięci.
Strony są uznawane za wolne lub używane. Wolne strony to nieużywana pamięć RAM. Używane strony to pamięć RAM, która jest aktywnie używana przez 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żąca do jednego procesu i nieudostę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ą
- Współdzielona: 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żąca do jednego procesu i nieudostę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 do radzenia sobie z sytuacjami, w których brakuje pamięci. Więcej informacji na ten temat znajdziesz w następnej sekcji tego dokumentu.
Zarządzanie małą ilością pamięci
Android ma 2 główne mechanizmy radzenia sobie z sytuacjami, w których brakuje pamięci: demona wymiany jądra i mechanizm low-memory killer.
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 odwołać się 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ęć w RAM (wolne strony). Jeśli proces spróbuje dotknąć 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 zamykać procesy.
Rysunek 3. Zmodyfikowana strona została przeniesiona do zRAM i skompresowana
Mechanizm low-memory killer
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 brakuje pamięci i że powinna zmniejszyć
przydział. Jeśli to nie wystarczy, jądro zacznie zamykać procesy, aby zwolnić pamięć. W tym celu używa mechanizmu low-memory killer (LMK).
Aby zdecydować, który proces zamknąć, LMK używa wyniku "brak pamięci (OOM)" o nazwie
oom_adj_score
aby określić priorytet uruchomionych procesów. Najpierw zamykane są procesy z wysokim wynikiem. Najpierw zamykane są aplikacje działające w tle, a na końcu procesy systemowe. W tabeli poniżej znajdziesz kategorie wyników LMK od najwyższego do najniższego. Najpierw zostaną zamknięte elementy z kategorii o najwyższym wyniku, czyli z pierwszego wiersza:
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 zamknie 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 program uruchamiający. Jej zamknięcie 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. Zamknięcie 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 zamknięciu tych procesów telefon może się zrestartować.
Natywne: procesy niskiego poziomu 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 współdzielone. Aplikacje, które mają dostęp do tej samej usługi lub biblioteki, będą współdzielić strony pamięci. Na przykład Usługi Google Play i aplikacja do gier mogą współdzielić 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 współdzielone przez 2 aplikacje (środek)
Aby określić wykorzystanie pamięci przez aplikację, można użyć dowolnego z tych wskaźników:
- Resident Set Size (RSS): liczba stron współdzielonych i niewspółdzielonych używanych przez aplikację.
- Proportional Set Size (PSS): liczba stron niewspółdzielonych używanych przez aplikację i równomierny rozkład stron współdzielonych (np. jeśli 3 procesy współdzielą 3 MB, każdy proces otrzymuje 1 MB w PSS).
- Unique Set Size (USS): liczba stron niewspółdzielonych używanych przez aplikację (strony współdzielone 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ą współdzielone i przez ile procesów. RSS nie rozróżnia stron współdzielonych i niewspółdzielonych (co przyspiesza obliczenia) i lepiej nadaje się do śledzenia zmian w alokacji pamięci.
Diagnozowanie najważniejszych ścieżek użytkownika (CUJ) z dużym wykorzystaniem pamięci
Podczas badania problemów z pamięcią warto zidentyfikować najważniejsze ścieżki użytkownika (CUJ) w aplikacji, które powodują duże wykorzystanie pamięci. Są to konkretne przepływy pracy, które z natury wymagają znacznej alokacji pamięci. Typowe najważniejsze ścieżki użytkownika (CUJ) z dużym wykorzystaniem pamięci to:
- wczytywanie i manipulowanie złożonymi multimediami lub dużymi bitmapami;
- hostowanie instancji
WebView.
Jeśli Twoja aplikacja korzysta z treści internetowych, instancje WebView mogą często stać się ukrytym wąskim gardłem pamięci ze względu na architekturę wieloprocesową i wykonywanie kodu natywnego. Szczegółowe informacje o diagnostyce, sprawdzonych metodach dotyczących cyklu życia i narzędziach
dostosowanych do treści internetowych znajdziesz w artykule Zarządzanie pamięcią WebView i jej diagnozowanie.
Dodatkowe materiały
- Omówienie zarządzania pamięcią
- Procesy i cykl życia aplikacji
- Wykorzystanie pamięci w Androidzie – prezentacja na Google I/O
- Pamięć w Androidzie i gry – prezentacja na Google I/O
- Demon low-memory killer w Androidzie
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Czas uruchomienia aplikacji