-->

niedziela, 12 sierpnia 2012

OutOfMemoryError - Android

Zaczynając pisać aplikacje na Androida nie przywiązywałem zbyt dużej wagi do jakości kodu i optymalizacji. To pociągnęło za sobą skutki w postaci błędów zgłaszanych przez użytkowników Milionera. Najczęstszym błędem przewijającym się w raportach był właśnie tytułowy błąd przepełnienia pamięci, dokładnie: java.lang.OutOfMemoryError: bitmap size exceeds VM budget...

Mimo że na moim Desire Z wszystko chodziło tak jak powinno to nawet lepsze telefonu z Androidem miały ten problem. Pierwszym krokiem było zorientowanie się jaka jest dostępna pamięć w każdej kolnej wersji Androida i jak to wszystko działa. W Androidzie wyróżniamy heap size czyli pamięć do której lokowane są nowo tworzone obiekty. Na starszych Androidach 1.6 ten obszar wynosił 16 MB. Dla wersji 2.1 to już 24 MB. Desire Z z Androidem 2.3.3 ma 32 MB. Oczywiście nie są to sztywne wartości i gorsze telefony mają mniej pamięci na aplikacje.

Warto pamiętać że istnieje także garbage collector, czyli coś w rodzaju sprzątacza. Niepotrzebne, niepowiązane obiekty są usuwane a tym samym zwalniana jest część pamięci. W wersji 2.3 garbage collector pracuje częściej i szybciej niż w 2.1. Choć i tak dla dynamicznej rozgrywki 2D/3D nie jest polecane wywoływanie go, ponieważ da się odczuć negatywny wpływ na płynność animacji.

Winą przepełniania była animacja z 11 klatek (pliki .jpg mocno skompresowane). Można było sobie poradzić w taki sposób:



Wykrywamy heap size, jeśli jest więcej niż 30 MB to możemy odtwarzać animację. To załatwiło sprawę dla słabszych telefonów (Galaxy Mini itp.), ale nie rozwiązało problemu całkowicie. Pomiędzy rozgrywkami użytkownicy trafiali nadal na ten błąd i znów wszystko się sypało. Powodem było nie czyszczenie pamięci po skończonej rozgrywce. Po każdej grze coraz więcej pamięci było zajętej przez animację a garbage collector przez istniejące referencje obiektów nie mógł tego ruszyć. Rozwiązanie takiego problemu:




Kluczową metodą jest zastąpienie animacji czymś "lżejszym" czyli np. kolorem i wywołanie System.gc(). Jest to przeciążona metoda onDestroy() dlatego nie musimy w takich przypadkach obawiać się o opóźnienia. Powyższy zabieg skutecznie przerwał serię wspomnianych błędów, być może nie jest bardzo elegancki ale działa ;]

Brak komentarzy:

Publikowanie komentarza