Android: come funziona Bitmap recycle ()?


89

Diciamo che ho caricato un'immagine in un oggetto bitmap come

Bitmap myBitmap = BitmapFactory.decodeFile(myFile);

Ora, cosa succederà se carico un'altra bitmap come

myBitmap = BitmapFactory.decodeFile(myFile2);

Cosa succede al primo myBitmap? Ottiene Garbage Collected o devo raccoglierlo manualmente prima di caricare un'altra bitmap, ad es. myBitmap.recycle()?

Inoltre, esiste un modo migliore per caricare immagini di grandi dimensioni e visualizzarle una dopo l'altra durante il riciclaggio?

Risposte:



23

Penso che il problema sia questo: nelle versioni pre-Honeycomb di Android, i dati bitmap grezzi effettivi non sono archiviati nella memoria della VM ma nella memoria nativa. Questa memoria nativa viene liberata quando l' Bitmapoggetto java corrispondente è GC.

Tuttavia , quando si esaurisce la memoria nativa, il dalvik GC non viene attivato, quindi è possibile che l'app utilizzi pochissima memoria java, quindi dalvik GC non viene mai richiamato, ma utilizza tonnellate di memoria nativa per le bitmap che alla fine causa un errore OOM.

Almeno questa è la mia ipotesi. Per fortuna in Honeycomb e versioni successive, tutti i dati bitmap sono archiviati nella VM, quindi non dovresti usarli recycle()affatto. Ma per i milioni di 2,3 utenti (frammentazione scuote il pugno ), dovresti usare recycle()ove possibile (una seccatura enorme). O in alternativa potresti essere in grado di invocare il GC invece.


21

Dovrai chiamare myBitmap.recycle () prima di caricare l'immagine successiva.

A seconda dell'origine del tuo myFile (ad esempio, se è qualcosa che non hai controllo sulla dimensione originale), quando carichi un'immagine invece di ricampionare semplicemente un numero arbitrario, dovresti ridimensionare l'immagine alla dimensione del display.

if (myBitmap != null) {
    myBitmap.recycle();
    myBitmap = null;
}
Bitmap original = BitmapFactory.decodeFile(myFile);
myBitmap = Bitmap.createScaledBitmap(original, displayWidth, displayHeight, true);
if (original != myBitmap)
    original.recycle();
original = null;

Memorizzo nella cache displayWidth e displayHeight in una statica che ho inizializzato all'inizio della mia attività.

Display display = getWindowManager().getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();

3
Non è necessario chiamare recycle (), è solo una buona idea se vuoi liberare subito la memoria.
Karu

13
La risposta accettata dice "Se vuoi liberare memoria al più presto, dovresti chiamare recycle ()". La tua risposta dice "Dovrai chiamare myBitmap.recycle ()". C'è una differenza tra "dovrebbe" e "necessario", e in questo caso quest'ultimo non è corretto.
Karu

1
Il contesto è importante. La domanda era "Inoltre esiste un modo migliore per caricare immagini di grandi dimensioni e visualizzarle una dopo l'altra riciclando lungo il percorso".
djunod

3
A partire da Android 4.1, l'esempio sopra potrebbe non funzionare perché createScaledBitmap può restituire in alcuni casi la stessa istanza dell'originale. Ciò significa che devi controllare l'originale! = MyBitmap prima di riciclare l'originale.
Jeremyfa

1
@Jeremyfa Restituisce l'immagine originale solo se si specifica una larghezza e un'altezza identiche all'originale. In tal caso, il ridimensionamento è discutibile, quindi potrebbe anche salvare alcuni processi saltandolo e restituendo invece l'immagine originale. Tuttavia non dovrebbe "rompere" nulla ...
Jabari

11

Una volta che la bitmap era stata caricata in memoria, infatti, era composta da dati in due parti. La prima parte include alcune informazioni sulla bitmap, un'altra parte include informazioni sui pixel della bitmap (è costituita da un array di byte). La prima parte esiste nella memoria utilizzata di Java, la seconda parte nella memoria utilizzata C ++. Può utilizzare direttamente la memoria dell'altro. Bitmap.recycle () viene utilizzato per liberare la memoria di C ++. Se lo fai solo, il GC raccoglierà la parte di java e la memoria di C. viene sempre utilizzata.


+1 per un modo interessante ma molto buono di descrivere il motivo per cui la memoria non è disponibile per la GC immediata - bella.
Richard Le Mesurier

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.