Testuję na Android 3.1, opcja dużego heapsize, około 250M dostępnej pamięci.Błąd fragmentacji pamięci Android GC. Obejście?
ustawić następujący kod do uruchomienia ilekroć wcisnął przycisk Test w preferencjach mojej aplikacji:
float [][][]foo = new float[3][2048][2048];
Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888);
bm.recycle();
bm = null;
foo = null;
mam dużo pamięci do tego - mogę nacisnąć przycisk kilka razy bez problemu.
Ale jeśli nadal uderzam w przycisk, w końcu (mniej niż 20 trafień) umiera z OutOfMemory. [Zwykle w android.graphics.Bitmap.nativeCreate (Native Method)]
Nic innego się nie dzieje - nigdy nie muszę opuszczać PreferencjiAktywność. Jest mała toast, który jest również wyświetlany po naciśnięciu przycisku, więc trwa mała aktywność w innym interfejsie użytkownika.
Czy to z powodu fragmentacji, czy po prostu strasznego błędu w kodzie Bitmapy i/lub GC? Czy robię coś głupiego? (Niech to będzie głupie ...)
Czy ktoś ma obejście? Ponieważ powyższe jest dość reprezentatywne dla tego, co mój kod musi zrobić za każdym razem, gdy użytkownik go wywołuje, a teraz, pomimo skrupulatnego usuwania zmiennych, umiera po kilku użyciach. (I zostało to doprowadza mnie do orzechów przez długi czas!)
[Aktualizacja]
I potwierdziły, że jest to bug problem fragmentacji lub GC, jak nora sterty pokazuje mi tylko gdy jest za pomocą 5,6M bezczynność (brak przecieków) osiąga wartość około 26 M podczas przetwarzania. (Natywny stos pozostaje poniżej 4M.) Podczas gdy sterty java w międzyczasie rośnie do limitu 280M na moim urządzeniu testowym, w którym to momencie zacząłem otrzymywać wyjątki OutOfMemory. Tak więc używam tylko 10% dostępnej sterty w szczycie, ale otrzymuję OutOfMemory.
[Dodanie wywołania do System.gc() niestety rozwiązuje prosty przypadek testowy podany powyżej. Mówię niefortunnie, ponieważ (A) nie powinno to mieć znaczenia, i (B), ponieważ już to nazywam regularnie w moim prawdziwym kodzie, więc to oznacza, że mój prosty przypadek testowy powyżej jest zbyt prosty.]
Czy ktoś jeszcze biegnie zaangażowany w to? Jakiekolwiek obejścia? Czy istnieje ładny sposób na ponowne uruchomienie mojej aplikacji?
[Aktualizacja]
Kolejna wersja niezawodnie powoduje OutOfMemory w ciągu 3 do 4 wywołań (naciśnięcia przycisku):
float [][][]foo = new float[3][2048][2048];
Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888);
int []bar = new int[3*2048*2048];
bm.recycle();
bm = null;
System.gc();
foo = null;
System.gc();
bar = null;
System.gc();
śledzenia pamięci przedstawia stosu rosnącego stopniowo każdego wywołania aż osiągnie limit i umiera. Jeśli usunę jedną z trzech alokacji, osiągnie równowagę i przetrwa w nieskończoność. Usunięcie wszystkich oprócz ostatniego gc() powoduje, że umrze nieco wcześniej.
Powiedziałbym, że jest to problem fragmentacji, a nie błąd gc jako taki. Jeśli ktokolwiek wie, jak to naprawić, daj mi znać. Przyporządkowanie int [] służy do zapisania mapy bitowej, więc nie mam możliwości przydzielenia jej jako tablicy 2d (ograniczenie biblioteki Android Bitmap).
Nie wiem, czy to pomoże, ale dalvik korzysta z [Mark-and-Sweep] (http://www.brpreiss.com/books/opus5/html/page424.html#SECTION0014300000000000000000) typu GC. Gdzie będzie próbował poczekać, aż cała dostępna pamięć zostanie użyta, a następnie wyczyść ją na raz (problemy z wydajnością, ponieważ musi przerwać przetwarzanie do GC). Być może wywołanie 'System.gc();' jest dokładnie tym, co jest potrzebne z tym problemem, ponieważ GC oczekuje mniejszych obiektów. – Ancantus
@Accantus - Niestety, jak już wspomniałem, wywołuję System.gc() po każdej operacji recycle()/null w moim prawdziwym kodzie i nadal otrzymuję to zachowanie. Myślę, że jest to problem fragmentacji lub coś takiego jak System.gc() jest ignorowane lub zachowuje się inaczej w wątkach w tle. Byłbym skłonny zabić i ponownie uruchomić moją aplikację od zera, aby skompaktować pamięć, jeśli istnieje niezawodny sposób na to. Chciałbym również, aby zadzwonić, by powiedzieć mi, po GC, jak dużo sterty java jest wolną przestrzenią (co by mi natychmiast powiedział i na pewno, jeśli jest to problem fragmentacji lub niejasny wyciek). Czy jest jeden? – Brandyn
Yah, jak pewnie wiesz, nazywając 'System.gc();' po prostu zaznacza GC, aby zacząć, to niekoniecznie oznacza, że będzie w ogóle działał. W rzeczywistości szukałem problemów związanych z bitmapą GC, [to pytanie SO] (http://stackoverflow.com/questions/7852943/what-does-bitmaprecycle-in-android-honeycomb-actually-do) może pomóc. – Ancantus