2012-05-20 14 views
28

Jestem całkiem nowy w rozwoju Androida i nie mogę zrozumieć wyjątku Java Out of Memory. Wiem, że oznacza to, że moja aplikacja przekroczyła budżet maszyny wirtualnej, ale po wielokrotnym przeszukiwaniu go nadal nie wydaje mi się, aby rozumieć tę koncepcję. Obawiam się, że moja aplikacja zużywa zbyt dużo pamięci, ponieważ mam sześć przycisków na ekranie z dwiema mapami bitowymi dla każdego selektora, których rozmiar wynosi około 20 kb zgodnie z zakładką właściwości. Na moim zrootowanym G2x ustawiłem budżet VM na 12MB, zrestartowałem mój telefon i uruchomiłem moją aplikację bez żadnych problemów. Rozplątuję rysunki na każdym z nich onDestroy() i podpowiedź na GC, żeby tu również biegać. Po pewnym czasie korzystania z aplikacji w emulatorze klikam "Przyczyna GC" na ekranie DDMS, a wyniki są następujące: ID = 1, rozmiar sterty 6.133 MB, przydzielony 2.895 MB, bezpłatny 3.238 MB,% używany 47,20, # obiekty 52.623.Rozumienie Rozmiarów Androida Rozumienie Rozmiarów

To tutaj nie rozumiem, co się dzieje, mój emulator jest ustawiony na 24MB VM. Gdzie jest ta liczba? Rzeczywisty problem, który mam, polega na tym, że jeśli ustawię emulator na 16MB VM, moja aplikacja ulega awarii podczas drugiej aktywności z wyjątkiem braku pamięci. Jak to się stało, że nie zawiesił się na moim telefonie z VM ustawionym na 12 MB lub na moim starym telefonie HTC Magic z 12 MB pamięci VM? Myślicie też, że moja aplikacja zajmuje zbyt dużo pamięci? Nie mam pojęcia, czy te numery DDMS są dobre, czy nie. Dziękuję za Twój czas.

Jeśli chodzi o mój kod, mam każdy obraz określony w układach XML, nie robię z nim nic programistycznie, poza dodawaniem do nich odbiorców. Znalazłem ten fragment kodu tu i dodałem go do każdej działalności, że mam ...

@Override 
protected void onDestroy() { 
    super.onDestroy(); 

    unbindDrawables(findViewById(R.id.myRootLayout)); 
    System.gc(); 
} 

private void unbindDrawables(View view) { 
    if (view.getBackground() != null) { 
     view.getBackground().setCallback(null); 
    } 
    if (view instanceof ViewGroup && !(view instanceof AdapterView)) { 
     for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { 
      unbindDrawables(((ViewGroup) view).getChildAt(i)); 
     } 
     ((ViewGroup) view).removeAllViews(); 
    } 
} 

inaczej zrobić to dodać onClickListeners do przycisków, które mają PNG tła. Chciałbym nauczyć się programowo definiować tła przycisków, ale muszę mieć funkcje selektora, jak na fokusie, na prasie, nie skupiony, ale wciśnięty itp., Aby zmienić tło przycisków zgodnie z interakcją użytkownika. Sprawdziłem dokumenty na ten temat, ale wydaje się to przytłaczające, dlatego pomyślałem, że zacznę tutaj od podstaw zarządzania Heapsami i pracuję nad określeniem selektorów w kodzie. To może nie mieć sensu, ale czy istnieje "zdrowa" ilość alokacji pamięci, którą aplikacja może przydzielić, nie zbliżając się do wyjątku braku pamięci? Na przykład, jeśli aplikacja ma przydzielone 6 MB, powinno być w porządku, ale 8 MB będzie ją przesyłać, czy są jakieś ograniczenia w alokacji pamięci? Jeszcze raz dziękuję Alexowi Lockwoodowi za odpowiedź. Przeczytam i ponownie ją przeczytam, dopóki to nie będzie dla mnie sensowne.

Odpowiedz

50

Po ustawieniu budżetu maszyny wirtualnej na emulatorze/urządzeniu, co robisz, to mówienie sterty maksymalny dozwolony rozmiar. W czasie wykonywania sterta dynamicznie rośnie, gdy Dalvik VM żąda pamięci systemowej z systemu operacyjnego. Maszyna Dalvik VM zwykle rozpoczyna się od przydzielenia względnie małej sterty. Następnie po każdym uruchomieniu GC sprawdza, ile jest wolnej pamięci sterty. Jeśli stosunek sterty wolnej do sterty całkowitej jest zbyt mały, to maszyna Dalvik VM doda więcej pamięci do sterty (do maksymalnego skonfigurowanego rozmiaru sterty).

Mimo to powodem, dla którego nie widzisz "24 mb" na ekranie DDMS, jest to, że sterty nie osiągnęły maksymalnego rozmiaru. Pozwala to Androidowi na wykorzystanie już małej ilości pamięci dostępnej na urządzeniach przenośnych.

Jeśli chodzi o przyczynę awarii aplikacji na emulatorze, a nie na telefonie, wydaje się to dziwne (czy na pewno numery są poprawne?). Należy jednak pamiętać, że pamięć jest zarządzana dynamicznie, a całkowite wykorzystanie pamięci jest określane na podstawie wielu czynników zewnętrznych (prędkości/częstotliwości, przy której odbywa się wyrzucanie śmieci itp.).

Wreszcie, z powodów, o których wspomniałem powyżej, trudno byłoby powiedzieć na pewno, jak dobrze aplikacja zarządza pamięcią w oparciu o jedną linię informacji podaną powyżej. Naprawdę potrzebowalibyśmy zobaczyć twój kod.OutOfMemoryError s na pewno warto się martwić, więc z pewnością zajrzę do użycia pamięci w twojej aplikacji. Jedną z rzeczy, które możesz rozważyć, jest wypróbowanie obrazów bitmapowych w czasie wykonywania za pomocą połączeń z inSampleSize przy użyciu klasy BitmapFactory. Może to pomóc w zmniejszeniu ilości pamięci wymaganej do załadowania bitmap do rysowania. Albo to albo możesz zmniejszyć rozdzielczość twoich rysunków (chociaż 20 kb dla mnie brzmi dobrze).

+3

+1, bardzo pouczająca odpowiedź! –

+0

Dziękuję bardzo! Wiele się z tego nauczyłem. Dodaję trochę informacji na końcu pytania. –

+0

Komentarz do rozdzielczości "20 kb każdy brzmi dobrze" - AFAIK, nie ma znaczenia rozmiar * pliku * (który będzie mniejszy dla obrazów, które kompresują lepiej), ważne są * WYMIARY *; w pamięci, dla pełnego koloru, zajmie 4B na piksel, prawda? Dlatego ważne jest, aby zmienić rozmiar obrazu po załadowaniu go [dokumenty android - ładowanie wersji skalowanej do pamięci], w oparciu o rzeczywisty wymagany rozmiar dla bieżącego urządzenia. – ToolmakerSteve

16

Nawet jeśli twoja aplikacja nie osiągnie limitu sterty "24mb" (zmienia się w urządzeniach), możesz nadal mieć awarie, ponieważ Android potrzebuje trochę czasu, aby powiększyć przestrzeń sterty dla twojej aplikacji.

W mojej sytuacji tworzyłem i wyrzucałem kilka zdjęć w niewielkiej ilości czasu.

Dość często otrzymywałem OutOfMemoryError.

Wygląda na to, że Android nie był wystarczająco szybki, aby powiększyć przestrzeń sterty dla mojej aplikacji.

Uważam, że rozwiązałem ten problem, używając ustawienia largeHeap w pliku manifestu. Po włączeniu tego ustawienia Android pozostawia więcej wolnej pamięci za każdym razem, gdy rośnie w stos, minimalizując szansę trafienia w bieżący limit.

Nie używam limitu 24mb, ale ten largeHeap conf był bardzo przydatny.

Trzeba tylko ustawić largeHeap="true" na etykiecie zgłoszenia swojej AndroidManifest.xml

<application 
    android:icon="@drawable/ic_launcher" 
    android:label="@string/app_name" 
    android:largeHeap="true" 
    android:theme="@style/AppTheme" > 

Mimo to, upewnij się, że jesteś ostrożny, gdy do czynienia z obrazami, jak @Alex Lockwood poradził.

+16

Używaj largeHeap = "true" z najwyższą ostrożnością. Ponieważ użycie tego może niekorzystnie wpłynąć na wydajność twojej aplikacji. Ponieważ mówisz systemowi, aby zwiększył maksymalny limit sterty. Kiedy to nastąpi, więcej czasu zajmuje zbieranie śmieci. Jeśli sprawdzisz log, zobaczysz, że GC Pause time będzie większy. Idealnie powinno być między 2-5m. W tym przypadku może się różnić nawet do 30-45ms. Więc nie ustawiaj dużej własności sterty na true tylko dlatego, że kończy Ci się pamięć. Użyj go jako ostatniego kroku. W przeciwnym razie będzie to hit perfomance. –

+0

Rzeczywiście. W moim przypadku mam do czynienia z dużą ilością obrazów wysokiej jakości dynamicznie i przed użyciem opcji largeHeap zaimplementowałem kod: - załaduj obrazy próbkowane - zmień rozmiar obrazów, aby idealnie pasowały - czyszczenie nieużywanych obrazów z pamięci - buforowanie obrazów w "dysku" Wciąż miałem problemy, które zostały rozwiązane tylko dzięki opcji largeHeap. Mimo to używaj go tylko po wypróbowaniu wszystkich innych rzeczy, takich jak @SanalVarghese. – tbraun

+0

Dodając do tego, mam mnóstwo problemów z pamięcią mojej aplikacji, jej rozmiar znacznie wzrasta. W tym momencie może nie być efektywnie zestawiona, ale powinna być w stanie nie przekraczać limitu. Jednak nigdy nie uwolniłoby wielu zasobów. Z jakiegoś powodu robi to bardzo dobrze po zastosowaniu opcji largeHeap. Wielkie dzięki. –

Powiązane problemy