web-dev-qa-db-fra.com

Android: Comment fonctionne Bitmap recycle ()?

Disons que j'ai chargé une image dans un objet bitmap tel que

Bitmap myBitmap = BitmapFactory.decodeFile(myFile);

Maintenant, que se passera-t-il si je charge un autre bitmap comme

myBitmap = BitmapFactory.decodeFile(myFile2);

Qu'advient-il du premier myBitmap? Récupère-t-il les ordures ou dois-je les récupérer manuellement avant de charger une autre image, par exemple. myBitmap.recycle()?

En outre, existe-t-il un meilleur moyen de charger de grandes images et de les afficher les unes après les autres tout en recyclant?

81
Anuj Tenani

Le premier bitmap n'est pas ordures collectées lorsque vous décodez le second. Garbage Collector le fera plus tard quand il le décidera. Si vous souhaitez libérer de la mémoire dès que possible, appelez recycle() juste avant de décoder le second bitmap.

Si vous voulez charger une très grande image, vous devez la rééchantillonner. Voici un exemple: Étrange problème de mémoire insuffisante lors du chargement d’une image dans un objet Bitmap .

71
Fedor

Je pense que le problème est le suivant: sur les versions antérieures à Honeycomb d’Android, les données bitmap brutes ne sont pas stockées dans la mémoire VM) mais dans la mémoire native. Cette mémoire native est libéré lorsque l'objet Java Bitmap est défini par GC'd.).

Cependant, lorsque vous manquez de mémoire native, le dalvik GC n'est pas déclenché. Il est donc possible que votre application utilise très peu de mémoire Java, dalvik GC n’est jamais appelé, mais il utilise des tonnes de mémoire native pour les bitmaps, ce qui provoque une erreur de MOO.

Au moins c'est ce que je suppose. Heureusement, dans Honeycomb et ultérieurement, toutes les données bitmap sont stockées dans le VM). Vous ne devriez donc plus avoir à utiliser recycle(). Mais pour les millions d'utilisateurs de la 2.3 (fragmentation secoue le poing), vous devriez utiliser recycle() chaque fois que cela est possible (un problème énorme), sinon vous pourrez peut-être appeler le GC.

21
Timmmm

Vous devrez appeler myBitmap.recycle () avant de charger l'image suivante.

En fonction de la source de votre fichier (par exemple, si vous ne pouvez pas contrôler la taille d'origine), lors du chargement d'une image au lieu de simplement ré-échantillonner un nombre quelconque, vous devez redimensionner l'image à la taille d'affichage.

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;

Je cache les propriétés displayWidth et displayHeight dans une statique que j'ai initialisée au début de mon activité.

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

Une fois le bitmap chargé en mémoire, il était en fait constitué de deux données partielles. La première partie contient des informations sur le bitmap, une autre partie contient des informations sur les pixels du bitmap (constitué d’un tableau d’octets). La première partie existe dans Java la mémoire utilisée, la seconde partie existe dans la mémoire utilisée C++. Elle peut utiliser directement la mémoire de chacun. Bitmap.recycle () est utilisé pour libérer la mémoire de C++. Si vous ne le faites Pour ce faire, le GC collecte la partie de Java) et la mémoire de C est toujours utilisée.

10
Allen

Timmmm avait raison.

selon: http://developer.Android.com/training/displaying-bitmaps/cache-bitmap.html

En outre, avant Android 3.0 (API, niveau 11), les données de sauvegarde d'un bitmap étaient stockées dans une mémoire native qui n'était pas publiée de manière prévisible. , provoquant potentiellement une application dépasser brièvement ses limites de mémoire et se bloquer.

8
Jian