2009-09-07 11 views
6

Piszę MIDlet używając LWUIT i obrazy wydają się pochłaniać niesamowitą ilość pamięci. Wszystkie obrazy, których używam, to pliki PNG i są pakowane do pliku JAR. Załaduję je za pomocą standardowej metody Image.createImage (URL). Aplikacja ma wiele formularzy, a każda ma kilka etykiet i przyciski, ale jestem dość pewna, że ​​tylko aktywna forma jest przechowywana w pamięci (wiem, że nie jest ona zbyt godna zaufania, ale Runtime.freeMemory() zdaje się potwierdzać to).Obrazy JavaME - LWUIT pochłaniają całą pamięć

Aplikacja działa dobrze w rozdzielczości 240x320, ale przeniesienie jej do rozdzielczości 480 x 640 i użycie odpowiednio większych obrazów do interfejsu użytkownika zaczęło powodować pojawianie się błędów pamięci. To, co robi aplikacja, to między innymi pobieranie zdalnych obrazów. Aplikacja wydaje się działać dobrze, dopóki nie dojdzie do tego punktu. Po pobraniu kilku plików PNG i powrocie do głównego menu napotkano błąd braku pamięci. Oczywiście sprawdziłem ilość pamięci używanej w menu głównym i było to dość szokujące. To tylko dwie etykiety z obrazami i czterema przyciskami. Każdy przycisk ma trzy obrazy używane dla style.setIcon, setPressedIcon i setRolloverIcon. Obrazy mają rozmiar od 15 do 25 KB, ale usuwając dwa z trzech obrazów używanych dla każdego przycisku (łącznie 8 obrazów), Runtime.freeMemory() wykazały oszałamiające zmniejszenie pamięci o 1 MB.

Tak jak to widzę, albo mam dużo wycieków pamięci (co nie wydaje mi się, żebym to robił, ale przecieki pamięci nie są dokładnie znane jako łatwe do wyśledzenia), robię coś strasznie nie tak z obsługą obrazów lub naprawdę nie ma problemu i po prostu muszę zmniejszyć skalę.

Jeśli ktoś ma jakikolwiek wgląd do oferty, byłbym bardzo wdzięczny.

+1

rozwiązanie ale Tipp:.. zoptymalizować png z optipng (http://optipng.sourceforge.net/) - kawałki obrazów z niewielką liczbą kolorów często do 50% jego wielkości bez redukcji jakości – user181750

Odpowiedz

0

Czy myślałeś o tym, że może ładowanie tego samego obrazu z JAR-a, wiele razy, powoduje powstanie wielu oddzielnych obiektów obrazu (z identyczną zawartością), zamiast tworzyć ponownie jedną instancję dla pojedynczego obrazu? To moje pierwsze przypuszczenie.

+0

Każde zdjęcie używam więcej niż raz (i e to spora liczba) jest ładowany tylko raz jako obiekt obrazu. Wiele obiektów Button i Label w całej aplikacji jest tworzonych przy użyciu tego samego obiektu Image, ale jest to coś, czego nie mogę obejść. Od momentu zamieszczenia pytania udało mi się wypracować jeden sposób optymalizacji - najwyraźniej HttpConnection pochłania również sporo pamięci. Przeniesienie całej komunikacji HTTP do pojedynczego, osobnego wątku i uporządkowanie kodu, aby upewnić się, że zginie i śmieci są zbierane, jak tylko to zrobi, pomogło. –

1

Istnieje kilka rzeczy, które mogą być tutaj dzieje:

  • Możecie widzieli pamięć używaną przed zbierania śmieci, które nie odpowiadają rzeczywistej pamięci używanej przez aplikację.
  • Niektóre kody innych firm, które używasz, mogą łączyć niektóre wewnętrzne struktury danych w celu zminimalizowania alokacji. Choć łączenie jest realną strategią, czasami wygląda na przeciek. W takim przypadku sprawdź, czy istnieje interfejs API do "zamykania" lub "usuwania" obiektów, których nie potrzebujesz.
  • Wreszcie, naprawdę możesz mieć przeciek. W takim przypadku musisz uzyskać więcej informacji o tym, co dzieje się w maszynie wirtualnej emulatora (pamiętaj jednak, że nie musi to być ta sama maszyna wirtualna).

Upewnij się, że emulator korzysta z JRE 1.6 jako wirtualnej maszyny JVM. Jeśli potrzebujesz go do korzystania z bibliotek środowiska wykonawczego z błędnego JDK, użyj -Xbootclasspath:<path-to-rt.jar>.

Następnie, po aplikacji staje się w stanie, który chcesz zobaczyć, zrobić %JAVA_HOME%\bin\jmap -dump:format=b,file=heap.bin <pid> (jeśli nie znasz identyfikator procesu, użyj jps)

Teraz masz zrzut JVM sterta. Możesz go przeanalizować za pomocą jhat (jest w pakiecie JDK, nieco trudny w użyciu) lub w programach innych firm (moja preferencja to YourKit - jest komercyjna, ale mają one ograniczone czasowo licencje eval)

+0

Analiza zrzutu sterty jest zdecydowanie drogą do znalezienia nieszczelności i nieefektywnego wykorzystania pamięci. Eclipse ma jeden wbudowany. Okno> Otwórz perspektywę> Analiza pamięci. następnie otwórz plik zrzutu. – tom

1

Miałem podobny problem z LWUIT na Java DTV. Czy próbowałeś spłukiwać obrazy, gdy już ich nie potrzebujesz (getAWTImage(). Flush())?

2

Urządzenia przenośne mają zwykle bardzo niską pamięć. Musisz więc użyć kilku sztuczek, by zachować i używać pamięci.

Ten sam problem wystąpił przy naszym projekcie i rozwiązaliśmy go w ten sposób.

dla pobranych obrazów: Utwórz pamięć podręczną, w której umieszczasz swoje obrazy. Jeśli potrzebujesz obrazu, sprawdź, czy jest on w cachemapie, jeśli nie jest pobrany i umieść go tam, jeśli jest, użyj go. jeśli pamięć jest pełna, usuń najstarszy obraz z cachemap i spróbuj ponownie.

dla innych obrazów zasobów: przechowuj je w pamięci tylko tak długo, jak możesz je zobaczyć, jeśli ich nie widzisz, przerwij odwołanie, a gc zrobi to za Ciebie.

Mam nadzieję, że to pomoże.

1

Użyj plików i zasobów, jeśli to możliwe (pliki zasobów domyślnie używają EncodedImage. Przeczytaj javadoc dla takich. Inne komentarze są również poprawne, że musisz faktycznie obserwować ilość pamięci, nawet wysoką RAM zabrakło urządzeń Android/iOS pamięci dość szybko z wielu obrazów

Unikać skalowania, która skutecznie eliminuje EncodedImage

nie
Powiązane problemy