Android: BitmapFactory.decodeStream () manque de mémoire avec un fichier de 400 Ko avec 2 Mo de mémoire libre

Mon application frappe une erreur de MOO sur la ligne suivante dans la source:

image = BitmapFactory.decodeStream(assetManager.open(imgFilename)); 

Juste avant l’allocation qui provoque la suppression de l’application avec une erreur de MOO:

 (...) 08-05 21:22:12.443: I/dalvikvm-heap(2319): Clamp target GC heap from 25.056MB to 24.000MB 08-05 21:22:12.443: D/dalvikvm(2319): GC_FOR_MALLOC freed <1K, 50% free 2709K/5379K, external 18296K/19336K, paused 58ms 08-05 21:22:14.513: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K, 50% free 2709K/5379K, external 18296K/19336K, paused 101ms 08-05 21:22:14.903: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB 08-05 21:22:14.903: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2709K/5379K, external 18312K/19336K, paused 53ms 08-05 21:22:22.843: D/ddm-heap(2319): Heap GC request 08-05 21:22:22.963: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB 08-05 21:22:22.963: D/dalvikvm(2319): threadid=1: still suspended after undo (sc=1 dc=1) 08-05 21:22:22.963: D/dalvikvm(2319): GC_EXPLICIT freed 1K, 50% free 2710K/5379K, external 18312K/19336K, paused 116ms 

DDMS rapporte une image similaire sur l’état du tas:

 Heap Size: 5.254 MB Allocated: 2.647 MB Free: 2.607 MB %Used: 50.38% #Objects 49,028 

Un seul pas sur cette ligne entraîne une erreur de MOO:

 08-05 21:26:04.783: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed decode returned false 
  1. La taille du fichier référencé par “imgFileName” est <400 Ko sous Windows. Alors, pourquoi BitmapFactory.decodeStream essaie-t-il d'allouer 2 Mo?
  2. Pourquoi y a-t-il une erreur de MOO quand il semble y avoir suffisamment d’espace libre?

Cette application vise Android 2.2 et plus.

Merci d’avance!

La bibliothèque Android n’est pas très intelligente pour le chargement des images. Vous devez donc créer des solutions pour cela.

Dans mes tests, Drawable.createFromStream utilise plus de mémoire que BitmapFactory.decodeStream .

Vous pouvez modifier le schéma de couleurs pour réduire la mémoire (RGB_565), mais l’image perdra également en qualité:

 BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Config.RGB_565; Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options); 

Référence: http://developer.android.com/reference/android/graphics/Bitmap.Config.html

Vous pouvez également charger une image à l’échelle, ce qui diminuera considérablement l’utilisation de la mémoire, mais vous devez connaître vos images pour ne pas en perdre trop.

 BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options); 

Référence: http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html

Pour définir dynamicment l’inSampleSize, vous pouvez connaître la taille de l’image pour prendre votre décision:

 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; bitmap = BitmapFactory.decodeStream(stream, null, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; options.inJustDecodeBounds = false; // recreate the stream // make some calculation to define inSampleSize options.inSampleSize = ?; Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options); 

Vous pouvez personnaliser l’inSampleSize en fonction de la taille d’écran de l’appareil. Pour obtenir la taille de l’écran, vous pouvez faire:

 DisplayMesortingcs mesortingcs = new DisplayMesortingcs(); ((Activity) activity).getWindowManager().getDefaultDisplay().getMesortingcs(mesortingcs); int screenWidth = mesortingcs.widthPixels; int screenHeight =mesortingcs.heightPixels; 

Autres tutoriels: – http://developer.android.com/training/displaying-bitmaps/load-bitmap.htmlhttp://developer.android.com/training/displaying-bitmaps/index.html

Veuillez voir ceci pour un guide sur le chargement plus efficace des grandes images bitmap:

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

Un fichier image de 400 Ko peut facilement prendre 5 à 10 Mo de RAM.

La taille du fichier sur le disque ne coïncide pas nécessairement avec la taille du fichier en mémoire. Il est probable que le fichier soit compressé, ce qui ne sera pas le cas lors du décodage. Vous devez en tenir compte dans votre calcul.

Multipliez la taille de l’image (largeur x hauteur) par la profondeur de couleur de l’image pour obtenir la taille en mémoire de l’image.

Fondamentalement, vous pouvez résoudre votre problème en essayant de faire évoluer votre Bitmap et vous verrez la consommation de mémoire réduite. Pour ce faire, vous pouvez copier la méthode indiquée ici .

En outre, il existe une page dédiée à Android Developeres qui pourrait vous aider à mieux comprendre comment charger des fichiers Bitmaps volumineux. Regardez la documentation officielle.

J’ai résolu le problème OutOfMemoryError en utilisant la méthode ci-dessous

 private Bitmap downloadImageBitmap(Ssortingng sUrl) { this.url = sUrl; bitmap = null; try { BitmapFactory.Options options = new BitmapFactory.Options(); for (options.inSampleSize = 1; options.inSampleSize <= 32; options.inSampleSize++) { InputStream inputStream = new URL(sUrl).openStream(); try { bitmap = BitmapFactory.decodeStream(inputStream, null, options); inputStream.close(); break; } catch (OutOfMemoryError outOfMemoryError) { } } } catch (Exception e) { e.printStackTrace(); } return bitmap; } 

Bien que les réponses ci-dessus soient manifestement correctes, une meilleure pratique consiste également à définir explicitement la propriété bitmap / src d’ImageView sur null , quand elles ne sont plus utilisées, surtout lorsque votre activité est détruite. Toute autre ressource lourde (gros textes, audio, vidéo), etc. peut également être annulée. Cela garantit que les ressources sont libérées instantanément et n’attendent pas la collecte du GC.

Je change la taille de l’échantillonnage par 2. Mon problème est résolu. Mais assurez-vous que la qualité de l’image ne soit pas détruite.