Sto testando su android 3.1, un'opzione heapsize grande, circa 250M di memoria disponibile.Errore di frammentazione della memoria GC per Android. Soluzione?
ho impostato il seguente codice di essere eseguito ogni volta che mi ha colpito un pulsante Test preferenze di mia app:
float [][][]foo = new float[3][2048][2048];
Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888);
bm.recycle();
bm = null;
foo = null;
Ho un sacco di memoria per questo - posso colpire il pulsante di un paio di volte senza problemi.
Ma se continuo a premere il pulsante, alla fine (meno di 20 colpi) muore con OutOfMemory. [Solitamente in android.graphics.Bitmap.nativeCreate (metodo nativo)]
Non succede nient'altro: non devo mai lasciare PreferenzeAttività. C'è un piccolo Toast che viene visualizzato anche quando premo il pulsante, quindi è in corso una piccola quantità di altre attività dell'interfaccia utente.
Ciò è dovuto alla frammentazione o solo a un orribile errore nel codice Bitmap di Android e/o GC? O sto facendo qualcosa di stupido? (Si prega di lasciare che sia qualcosa di stupido ...)
Qualcuno ha una soluzione? Perché quanto sopra è abbastanza rappresentativo di ciò che il mio codice deve fare ogni volta che l'utente lo invoca, e in questo momento, nonostante una meticolosa cancellazione delle variabili, muore dopo alcuni usi. (E questo è stato me alla guida di noci per molto tempo!)
[Update]
Ho confermato che è un problema di frammentazione o GC bug, come un heap dump mostra che sto usando solo 5.6M quando inattivo (senza perdite) con un picco di circa 26 M durante l'elaborazione. (Inoltre, l'heap nativo rimane inferiore a 4M.) Mentre l'heap java nel frattempo cresce fino al limite di 280M sul mio dispositivo di test, a quel punto inizio a ricevere le eccezioni OutOfMemory. Quindi sto usando solo il 10% del mio heap disponibile al massimo, ma ricevo OutOfMemory.
[L'aggiunta di una chiamata a System.gc() purtroppo risolve il semplice caso di test che ho fornito sopra. Dico sfortunato perché (A) non dovrebbe fare la differenza, e (B) perché lo chiamo già regolarmente nel mio codice reale quindi significa che il mio semplice caso di test sopra è troppo semplice.]
Qualcun altro ha eseguito in questo? Qualche soluzione alternativa? C'è un modo elegante per riavviare la mia app?
[Update]
La seguente versione provoca affidabile OutOfMemory in 3 o 4 invocazioni (pressioni del tasto):
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();
tracing memoria mostra il cumulo in costante crescita ogni chiamata fino a raggiungere il limite e muore. Se rimuovo una delle tre allocazioni, raggiunge l'equilibrio e sopravvive indefinitamente. Rimuovendo tutto tranne l'ultimo gc() provoca la sua morte un po 'prima.
Direi che questo è un problema di frammentazione, non un bug gc di per sé. Se qualcuno sa come risolverlo, fammi sapere. L'allocazione int [] è per la scrittura di un Bitmap, quindi non ho la possibilità di allocarlo come array 2d (limitazione della libreria di Bitmap di Android).
Non so se questo sarà di aiuto, ma dalvik usa un [Mark-and-Sweep] (http://www.brpreiss.com/books/opus5/html/page424.html#SECTION0014300000000000000000) tipo GC. Dove cercherà di aspettare fino a quando tutta la memoria disponibile viene utilizzata, quindi ripulire tutto in una volta (problemi di prestazioni, perché ha bisogno di interrompere l'elaborazione in GC). Forse la chiamata 'System.gc();' è esattamente ciò che è necessario con questo problema, perché il GC si aspetta oggetti più piccoli. – Ancantus
@Ancantus - Sfortunatamente, come detto, chiamo System.gc() dopo ogni recycle()/null nel mio codice reale e ancora ottengo questo comportamento. Sto pensando che si tratti di un problema di frammentazione o qualcosa di simile a System.gc() che viene ignorato o si comporta in modo diverso nei thread in background. Sarei disposto a uccidere e riavviare la mia app da zero per compattare la memoria se ci fosse un modo affidabile per farlo. Mi piacerebbe anche una chiamata per dirmi, post-GC, quanto dell'heap java è lo spazio libero (che mi direbbe immediatamente e di sicuro se si tratta di un problema di frammentazione o di una perdita oscura). Ce n'è uno? – Brandyn
Yah come probabilmente sapete chiamare 'System.gc();' indica solo il GC per iniziare, non significa necessariamente che verrà eseguito. In realtà stavo facendo una ricerca in giro per problemi relativi alla bitmap GC, [questa domanda SO] (http://stackoverflow.com/questions/7852943/what-does-bitmaprecycle-in-android-honeycomb-actually-do) potrebbe aiutare. – Ancantus