Będąc w sklepie przy stoisku z gazetami zauważyłem na okładce bodajże "Komputer Świata" tytuł artykułu "Przyspiesz swojego Androida". Zaglądam do środka, a tam jednym ze sposobów na przyspieszenie systemu jest używanie różnego rodzaju "task killerów" :P "Ale bzdury piszą" pomyślałem i postanowiłem, że napiszę artykuł o zarządzaniu pamięcią w Androidzie.
Zwykle nie czytam "mainstreamowej" prasy komputerowej, bo mi się zazwyczaj ciśnienie podnosi na widok niskiego poziomu merytorycznego tych gazet. Praktycznie nie ma gazet z której można by czerpać wiedzę, a nie reklamy. Jedyną gazetą o tematyce komputerowej jaką czytam jest Linux Magazine, bo tam poziom jest niezmiennie wysoki i każdym wydaniem można się czegoś nowego nauczyć.
Ale wróćmy do zarządzania pamięcią w Androidzie. System ten sporo czerpie z Linuksa, który jest zawarty w Androidzie. Podstawowym założeniem systemu jest stwierdzenie, że pamięć nie może się marnować, czyli leżeć nieużywana. Pamięć jest po to, aby z niej korzystać. Mniejsze zużycie pamięci RAM wcale nie wydłuży pracy na baterii, bo czy pamięć jest zajęta czy wolna zużywa tyle samo prądu. Tylko użytkownicy Windows są nauczeni do zamykania aplikacji. Dlatego też wielkie jest ich zdziwienie, gdy widzą że większości aplikacji na Androida nie ma przycisku zamknij 


Jako użytkownik Androida nie musisz się martwić zamykaniem aplikacji. System sam zajmie się aplikacjami, które są już niepotrzebne w tym momencie. Gdy zachodzi potrzeba na większą ilość RAMu (np. gdy uruchamiamy wymagającą aplikację) system sam się reorganizuje w celu zwolnienia potrzebnej ilości pamięci.
Jak już wcześniej napisałem w Androidzie jest Linux, który zarządza pamięcią. W Linuksie na komputerze jest takie samo zarządzanie pamięcią RAM. Gdy jest dużo wolnego RAMu, Linux wykorzystuje go jako pamięć podręczną. Na przykład w momencie, gdy pisałem ten artykuł miałem uruchomioną tylko przeglądarkę (w tle chodzi kilka innych programów). Mam 3GB RAMu, a naprawdę wolnej pamięci zostało mi 340MB. 1.2 GB jest zajęte przez pamięć podręczną Linuksa, w której znajdują się najczęściej odczytywane z dysku dane.
Pierwszą różnicą między Linuksem desktopowym, a Androidem jest OOM Kill (Out Of Memory Kill). OOM Kill to funkcja kernela, która zarządza pamięcią w przypadku gdy pojawi się zapotrzebowanie na większą ilość RAMu niż aktualnie jest dostępna w systemie. W desktopowym Linuksie działania OOM Kill praktycznie nie zauważymy. W Androidzie jego funkcjonowanie jest na porządku dziennym.
Zanim wytłumaczę w jaki sposób działa OOM Kill zapoznajmy się z typami procesów w Androidzie:
- Foreground App - aplikacje, które są aktualnie uruchomione i są aktualnie na ekranie. Mogą to być również aplikacje systemowe, których pozornie nie widać.
- Visible App - aplikacje uruchomione w tle (nie wiem czemu nazywają się 'visible', bo niekoniecznie muszą być widoczne), które wykonują jakieś zadanie. Może to być na przykład Google Play, który sprawdza czy są nowe wersje aplikacji.
- Secondary Server - proces (usługa), która działa w tle i jest wykorzystywana przez którąś z działających aplikacji.
- Hidden App - aplikacje w tle czekające na podjęcie działania przez użytkownika.
- Content Provider - procesy odpowiadające za dostarczanie danych dla aplikacji i systemu. Mogą to być np. proces klawiatury, która odpowiada za słownik albo proces czytnika RSS dostarczający dane z kanałów.
- Empty App - aplikacje, z których użytkownik wyszedł i niczego już nie robią. Pozostają w pamięci, jeśli jest jeszcze wystarczająco wolna, aby szybciej się otworzyć gdyby użytkownik jeszcze jej potrzebował.
Jeśli będzie potrzeba wykorzystania większej ilości RAMu to aplikacje typu Empty App, Content Provider i Hidden App będą pierwsze do wyrzucenia z pamięci. Dodatkowo każda z aplikacji posiada OOM Priority (czasem zwana OOM Value). Jest to ważność procesu określana za pomocą liczby z zakresu -17 do 17 (-17 to najwyższy priorytet a 17 najniższy). Zatem jeśli proces posiada OOM Priority 12 wyleci z pamięci wcześniej, niż proces, który posiada OOM Priority 8.
Każdy z typów aplikacji wymienionych wyżej posiada również zdefiniowane ilości wolnego RAM (minfree), które powinny być przestrzegane przez system. Zazwyczaj aplikacje Foreground posiadają jej najmniej, ponieważ jako uruchomione i widoczne są najbardziej potrzebne.
Aby wytłumaczyć jak działa OOM Kill pokaże to na przykładzie telefonu HTC Wildfire, który posiada 384MB RAMu i dosyć łatwo doprowadzić do braku pamięci. Telefon ten posiada następujące domyślne (zdefiniowane przez producenta) ilości wolnego RAMu dla poszczególnych grup aplikacji:
- Foreground App - 14MB
- Visible App - 16 MB
- Secondary Server - 24 MB
- Hidden App - 28 MB
- Content Provider - 30MB
- Empty App - 32 MB
Jeżeli podczas używania systemu ilość wolnej pamięci spadnie do 32MB to system w pierwszej kolejności zaczyna zamykać aplikacje z grupy Empty App. Jeśli jeszcze jest za mało wolnego RAMu (30 MB) zamykane są aplikacje z grupy Content Provider. Gdy w Content Provider mamy np. YouTube z wartością OOM 11 i Twitter z wartością OOM 13, pierwszy wyleci Twitter. O kolejności zamykania procesów decyduje OOM Priority. Zamykanie procesów trwa do momentu spełnienia warunków minfree.
Według oficjalnej dokumentacji deweloperskiej Androida na poszczególne grupy aplikacji są przewidziane określone wartości OOM:
- Foreground App: od -16 do 0
- Visible App :1
- Secondary Server: 2
- Hidden App: od 3 do 7
- Content Provider: od 8 do 14
- Empty App: 15
Dlaczego smartfon zamula
Przyczyn może być kilka. Zauważyłem, że gdy zaczyna kończyć się pamięć RAM i schodzi poniżej 50MB w HTC Wildfire (nie mylić z pamięcią wewnętrzną telefonu czyli partycją /data) telefon zauważalnie zwalnia. Aby na bieżąco znać ilość wolnego RAMu, warto zainstalować na smartfonie aplikację do monitorowania systemu. Polecam Cool Tool. Aplikacja ta stałe wyświetlana jest na ekranie, więc cały czas przed oczami mamy ilość wolnej pamięci. Mała ilość RAMu powoduje zamykanie aplikacji przez OOM Kill i ponowne jej restarty, gdy pamięć znów się zwolni. Pamiętajmy, że nie tylko aplikacjom, ale również systemowi potrzebny jest RAM. W niektórych Androidach (CyanogenMOD) pamięć swap trzymana jest również w RAM, czyli tak zwany ZRAM (compcache).

Drugą przyczyną przytykania się Androida są zasobożerne aplikacje (np. Facebook). Gdy mało jest dostępnego wolnego RAMu, to powodem tego może być sporo otwartych aplikacji działających w grupach Visible App i Secondary Server. Te znajdują się dosyć wysoko jeśli chodzi o priorytety OOM. Kernel będzie je zamykał na samym końcu, a w tym czasie te aplikacje konkurują ze sobą w dostępie do mocy obliczeniowej procesora, który ma mniej czasu na pozostałe operacje. Warto przejrzeć aplikacje z tych grup za pomocą aplikacji Memory Managerlub Rom Toolbox Pro.


Kolejną przyczyną są rosnące wymagania aplikacji. Na to już nie mamy wpływu. Wychodzą coraz nowsze smartfony posiadające coraz więcej pamięci i lepsze procesory. Programiści przestają dbać o starsze telefony. Przykładem takiej aplikacji jest SwiftKey. Wersja 2 i X (czyli 3) chodziła na Wildfire (prawie) doskonale. W wersji 4 wymagania znacznie wzrosły i używanie tej aplikacji staje się mordęgą. Choć nadal uważam ją za najlepszą klawiaturę na Androida 

Ostatnio odkryłem również, że przenoszenie danych aplikacji na partycję ext karty SD też powoduje zwolnienie pracy oraz zawieszenia. W danych aplikacji znajdują się bazy danych SQLite, do których jest dużo operacji wejścia-wyjścia, szczególnie w aplikacjach działających w tle (np. Facebook Messenger). Może to powodować szybsze zużycie karty SD. Ważna jest również jej szybkość. Absolutne minimum to klasa 4. Ja przenosiłem dane aplikacji ręcznie linkując katalogi z /data/data do /data/sdext/data (punkt montowania partycji ext na karcie SD). Do przenoszenia plików APK, dalvik-cache czy bibliotek używam Link2SD.
Co możemy zrobić, aby zyskać więcej pamięci?
Wszystko zależy od tego, czy mamy uprawnienia roota. Jeśli nie to niestety niewiele. Możemy szukać lżejszych odpowiedników naszych aplikacji, bądź odinstalować niepotrzebne aplikacje. Gdy jednak mamy roota nasze możliwości rosną.
Przy pomocy Memory Managera, o którym wspomniałem wcześniej, możemy modyfikować wartości minfree. Większa ilość pamięci (większa wartość minfree), która ma być wolna powoduje wcześniejsze zamykanie aplikacji. Zazwyczaj zaleca się zwiększanie wartości minfree tylko dla grupy Empty App, Content Provider i Hidden App. W umiarkowanym stopniu możemy bezpiecznie modyfikować również pozostałe grupy o podwyższonym OOM Priority. Zbyt duże zwiększenie minfree może powodować częstsze zamykanie aplikacji. Trzeba zachować umiar, gdyż możemy zamknąć w ten sposób proces od którego zależy np. Launcher. Inne objawy za dużej wartości minfree w danej grupie to samoczynne zamykanie się aplikacji, w której aktualnie pracujemy, całkowite zawieszenie systemu (dalvik crash) i nawet restarty.
Powyższa metoda zmian wartości minfree najlepiej gdyby była przetestowana metodą prób i błędów. Każdy smartfon może mieć inną ilość wolnej pamięci przy której będzie dobrze pracował. Na przykład HTC Wildfire dobrze chodzi na 50MB wolnej pamięci. Zejście poniżej tej wartości może skutkować zamulaniem systemu.
Od razu może do głowy przyjść pytanie czy da się manipulować OOM Priority? Da się, ale jeśli zmienimy priorytet zostanie on z powrotem przywrócony przez system.
Czy warto używać "task killerów"?
Generalnie nie warto. Zabijanie wielu aplikacji jednocześnie powoduje większe zużycie procesora, a co za tym idzie i baterii. Zabijane w tej sposób aplikacje posiadające usługi i tak same się uruchomią, gdy będą spełnione odpowiednie warunki, na przykład dostęp do Internetu (apki Facebook czy Twitter). Skutecznie zabije to tylko aplikacje, które nie mają uruchomionych własnych usług.
Zamiast "task killerów" radzę wykorzystać wbudowany w kernel mechanizm OOM Kill. Dzięki niemu jeśli wytypujemy grupę aplikacji, która najbardziej pożera RAM, a nie są to aplikacje niezbędne do prawidłowego funkcjonowania systemu, możemy bezproblemowo zwalniać pamięć. Bez instalacji dodatkowych killerów. Android sam o to zadba.
Jest jeden wyjątek od powyższej reguły: możemy zakończyć aplikację jeśli źle działa lub nie odpowiada. Najlepiej jest wykorzystać do tego systemowe informacje o aplikacji i przycisk Zakończ. Ta metoda jest bardziej łagodna. W ten sposób możemy również pozbyć się ikon tej aplikacji z paska stanu. Zabijając "killerem" daną aplikację możemy pozbyć się tylko jednego procesu, podczas gdy inne danej aplikacji mogą pracować dalej i oczekiwać na interakcję od tego zabitego.

Zamykanie w sposób przewidziany przez system, czyli z informacji o aplikacji jest trochę uciążliwe. Trzeba wejść w ustawienia, wyszukać aplikację, wyświetlić informacje i dopiero zamknąć. Jest na to szybkie rozwiązanie - Close App. Po kliknięciu aplikacji wyświetla się lista uruchomionych apek. Wybieramy jedną i wyświetlają się od razu systemowe informacje o aplikacji i tam jest też przycisk do zamknięcia. Możemy również tym sposobem zamknąć aplikacje systemowe. A co najważniejsze Close App jest malutki - 24 kilobajty. I nie wymaga roota 

Mam nadzieje, że udało mi się w sposób jasny wytłumaczyć jak działa zarządzanie pamięcią w Androidzie, oraz jak optymalizować ustawienia, aby efektywniej wykorzystać pamięć i moc obliczeniową smartfona. Jeśli pojawią się pytania co do artykułu proszę je zadawać w komentarzach, na pewno odpowiem.