67 votes

Android: BitmapFactory.decodeStream() de la mémoire avec une 400KB fichier avec 2 mo de libre tas

Mon application est de frapper un OOM erreur à la ligne suivante dans la source:

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

Juste avant l'allocation qui entraîne l'application à être tués avec un OOM erreur:

(...)
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 rapports une image similaire à propos de l'état de la pile:

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

Le pas à pas sur cette ligne les résultats dans un OOM erreur:

08-05 21:26:04.783: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K, 50% free 2710K/5379K, external 18312K/19336K, paused 57ms
08-05 21:26:05.023: E/dalvikvm-heap(2319): 2097152-byte external allocation too large for this process.
08-05 21:26:05.163: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:26:05.163: E/GraphicsJNI(2319): VM won't let us allocate 2097152 bytes
08-05 21:26:05.163: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2710K/5379K, external 18312K/19336K, paused 30ms
08-05 21:26:05.283: D/skia(2319): --- decoder->decode returned false
  1. La taille du fichier référencé par "imgFileName" est signalé à être < 400K sur Windows. Alors, pourquoi ne BitmapFactory.decodeStream essayer d'allouer 2 MO?
  2. Pourquoi est-il un OOM erreur quand il semble y avoir suffisamment d'espace libre?

Cette application est le ciblage d'Android 2.2 et plus.

Merci à l'avance!

90voto

Paulo Cheque Points 335

Android bibliothèque n'est pas si intelligent pour le chargement des images, de sorte que vous avez à créer des solutions de contournement pour ce.

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

Vous pouvez changer le schéma de Couleur pour la réduction de la mémoire (RGB_565), mais l'image sera trop perdre 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 va diminuer de beaucoup l'utilisation de la mémoire, mais vous devez savoir que vos images afin de ne pas perdre trop de qualité.

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 la inSampleSize de façon dynamique, vous voudrez peut-être savoir 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 la inSampleSize selon la taille de l'écran de l'appareil. Pour obtenir la taille de l'écran, vous pouvez:

DisplayMetrics metrics = new DisplayMetrics();
((Activity) activity).getWindowManager().getDefaultDisplay().getMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight =metrics.heightPixels;

D'autres tutoriels: - http://developer.android.com/training/displaying-bitmaps/load-bitmap.html - http://developer.android.com/training/displaying-bitmaps/index.html

42voto

Michell Bak Points 6312

Veuillez consulter ce guide sur le chargement d'un grand Bitmaps de manière plus efficace:

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

A 400 KO fichier image peut facilement prendre de 5 à 10 MO de RAM.

8voto

nEx.Software Points 4054

La taille du fichier sur le disque ne doit pas nécessairement coïncider avec la taille du fichier en mémoire. Les Chances sont probablement que le fichier est compressé, ce qui ils ne seront pas 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 avoir la taille en mémoire de l'image.

3voto

yugidroid Points 2569

Fondamentalement, vous pouvez résoudre votre problème en essayant de mettre à l'échelle votre Bitmap et vous verrez la consommation de mémoire réduite. Pour le faire, vous pouvez copier il méthode indiquée ici.

Aussi, il y a une page dédiée à Android Developeres qui pourraient vous aider à mieux comprendre comment charger les grandes images bitmap. Jetez un oeil à l'officiel de la documentation.

1voto

rishabh Points 627

Alors que les réponses ci-dessus sont évidemment correct, une meilleure pratique consiste également à définir explicitement l'ImageView bitmap/src propriété null, quand elles ne sont plus utilisées, surtout si votre activité est en train d'être détruit. Toute autre heavy duty ressources( grand texte, audio, vidéo), etc. peut également être annulé. Cela garantit que les ressources sont libérées immédiatement et ne pas attendre que la GC à collecter.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X