web-dev-qa-db-fra.com

android - exception de mémoire insuffisante lors de la création d'un bitmap

Je reçois le message d'erreur suivant après avoir créé bitmap une seconde fois:

04-17 18:28:09.310: ERROR/AndroidRuntime(3458): Java.lang.OutOfMemoryError: bitmap size exceeds VM budget

this._profileBitmap = Bitmap.createBitmap(_profileBitmap, xCoor,  yCoor, width, height);

À partir du journal:

04-17 18:27:57.500: INFO/CameraCropView(3458): Original Photo Size: W 1536 x H 2048   
04-17 18:28:06.170: INFO/CameraCropView(3458): xCoor: 291   
04-17 18:28:06.170: INFO/CameraCropView(3458): yCoor: 430    
04-17 18:28:06.170: INFO/CameraCropView(3458): Width: 952  
04-17 18:28:06.170: INFO/CameraCropView(3458): Height: 952  

Puisque l'image est énorme, j'obtiens l'erreur. Mais ce qui est intéressant, c’est que l’erreur ne se produit pas la première fois, mais lorsque je prends la photo pour la deuxième fois, ce qui me fait penser que ce profilBitmap n’est PAS détruit. Comment puis-je nettoyer cela?

11
dropsOfJupiter

J'ai eu le même problème et le réparer de cette façon:

Mon application pesait environ 18 Mo. Quand je vois combien de mémoire restait libre, je fus choqué - 654 Ko (sur 1 Go de RAM!). Je viens donc de supprimer presque toutes les images du projet et de les télécharger d'Internet au premier démarrage, et d'utiliser les images de la carte SD en cas de besoin.

Pour vérifier la mémoire totale/libre pour l'utilisation de votre application:

 Runtime.getRuntime().totalMemory();
 Runtime.getRuntime().freeMemory();

EDIT: J'ai oublié l'essentiel - ajoutez dans votre manifeste, entre les balises d'activité, cette ligne:

Android: largeHeap = "true"

13
Vitas

Il existe de nombreux problèmes avec les exceptions de mémoire avec les bitmaps sur Android, dont beaucoup sont discutés sur stackoverflow. Il serait probablement préférable que vous examiniez les questions existantes pour voir si les vôtres correspondent à celles qui existent déjà. Sinon, écrivez en quoi votre situation est différente.

Quelques exemples:

Exception de mémoire insuffisante en raison de la taille importante des images bitmap

Android: exception de mémoire insuffisante dans Galerie

Exception de gestion de mémoire insuffisante sur le traitement d'images pour Android

etc: https://stackoverflow.com/search?q=Android+out+of+memory+exception+bitmap

12
ThomasW

Astuces de traitement de bitmap Android

Maintenant, voici quelques conseils que vous pouvez suivre et que vous pouvez éviter pour les exceptions de mémoire insuffisante dans votre application Android.

  1. Toujours utiliser le contexte d'activité au lieu du contexte d'application. car le contexte de l'application ne peut pas être récupéré. Et libérez des ressources à la fin de votre activité. (le cycle de vie de l’objet devrait être identique à celui de l’activité).

2 Quand l'activité se termine. Vérifiez HEAP DUMP (outil d’analyse de mémoire dans Android Studio).

HEAP DUMP contient des objets résultant d'une activité terminée, il y a une fuite de mémoire. Passez en revue votre code et identifiez ce qui cause une fuite de mémoire.

  1. Toujours utiliser inSampleSize

Maintenant, qu'est-ce que inSampleSize? Avec l'aide de inSampleSize, vous indiquez en fait au décodeur de ne pas capturer chaque pixel en mémoire, mais plutôt de sous-échantillon d'image. Cela entraînera le chargement de moins de pixels dans mémoire que l'image d'origine. vous pouvez indiquer au décodeur de saisir tous les 4 pixels ou tous les deux pixels de l'image d'origine. si inSampleSize est égal à 4. Le décodeur renverra une image représentant 1/16 du nombre de pixels de l'image d'origine.

alors combien de mémoire avez-vous économisée? calculer :)

  1. Lisez les dimensions bitmap avant de les charger en mémoire.

    Comment lire les dimensions bitmap avant de charger l’image en mémoire peut vous aider à éviter les
    erreur de mémoire? Apprenons

    utilisez inJustBounds = true

voici une technique à l'aide de laquelle vous pouvez obtenir une dimension d'image avant de la charger en mémoire

 BitmapFactory.Options options = new BitmapFactory.Options();
 options.inJustDecodeBounds = true;
 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.myimage,    options);
 int imageHeight = options.outHeight;
 int imageWidth = options.outWidth;
 String imageType = options.outMimeType;

L'extrait de code ci-dessus ne nous donnera aucune image/bitmap. il retournera null pour bitmap Object. mais retournera certainement la largeur et la hauteur de cette image. qui est R.id.myimage.

Maintenant, vous avez la largeur et la hauteur de l'image. vous pouvez agrandir ou réduire l'image en fonction de ces facteurs:

  • ImageView taille qui sera utilisé pour afficher l'image.
  • Quantité de mémoire disponible. vous pouvez vérifier la quantité de mémoire disponible à l'aide d'ActivityManager et de getMemoryClass. 
  • Taille de l'écran et densité de l'appareil.

    1. Utiliser la configuration bitmap appropriée

    Les configurations bitmap correspondent à l’espace colorimétrique/profondeur de couleur d’une image. La configuration bitmap par défaut dans Android est RGB_8888, soit 4 octets par pixel.

Si vous utilisez le canal de couleur RGB_565, utilisez 2 octets par pixel. la moitié de l'allocation de mémoire pour la même résolution :)

  1. Utilisez la propriété inBitmap à des fins de recyclage.

  2. Ne créez pas d'objet Drawable statique, car il ne peut pas être récupéré.

  3. Demander un grand tas dans le fichier manifeste.

  4. Utilisez plusieurs processus si vous effectuez beaucoup de traitement d'image (tâche gourmande en mémoire) ou utilisez NDK (développement natif à l'aide de c, c ++).

5
Hammad Tariq

Cela se produit parce que vous chargez le bitmap directement, ce qui consomme beaucoup de mémoire. Utilisez plutôt une version réduite de l'image dans _profileBitmap. Cet homme l'explique assez bien. ] http://androidcocktail.blogspot.in/2012/05/solving-bitmap-size-exceeds-vm-budget.html

4
android

Vous pouvez utiliser un vecteur Drawable. Il utilise un fichier xml pour décrire votre image et consomme donc moins de mémoire. Pour ce faire, vous devez utiliser le format SVG pour vos images, puis générer le fichier xml en utilisant l’une des deux solutions suivantes:

  • Solution 1: utilisez le studio de ressources vectorielles dans Android Studio: cliquez avec le bouton droit de la souris sur Fichier dessinable dans votre projet -> nouveau -> ressource vectorielle
  • Solution 2: utilisez le site Web svg2Android: https://inloop.github.io/svg2Android

Consultez ce lien pour plus d'informations:
https://developer.Android.com/studio/write/vector-asset-studio.html

2
Marwen Doukh

Vous pouvez essayer d'appeler recycle () sur le bitmap lorsque vous avez terminé. Cela effacera toutes les données d'image et libérera de la mémoire. Si quelque chose essaie de dessiner le bitmap après cela, votre application va se bloquer. Si vous rencontrez un problème, cela peut vous aider à déterminer ce qui reste sur votre bitmap.

1
skorulis

J'avais ce problème parce que je modifiais une image une fois, puis la version modifiée une seconde fois, de sorte que trois versions de la même image (l'original et les deux versions modifiées) étaient en même temps en mémoire.

Je l'ai corrigé en changeant mon code d'édition d'image pour appliquer les deux modifications au même bitmap qu'une sorte de traitement par lot, divisant par deux le nombre de versions modifiées que mon application devait conserver en mémoire.

1
Andrew Koster

Avec des images plus grandes, évitez de les échantillonner dans un format plus petit. Utilisez l'exemple ci-dessous -

    File f = new File(selectedImagePath); 

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(new FileInputStream(f), null, options); 
    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, 720, 1280); //My device pixel resolution
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;    
    Bitmap bmpPic = BitmapFactory.decodeStream(new FileInputStream(f), null, options); 


    Bitmap bmpPic1 = Bitmap.createBitmap(bmpPic, 0, 0, bmpPic.getWidth(), bmpPic.getHeight(), mat, true);   
    img.setImageBitmap(bmpPic1);  //img is your ImageView

Référence - http://developer.Android.com/training/displaying-bitmaps/load-bitmap.html

0
amir ansari

J'ai eu le même problème lorsque le téléphone était éteint et rallumé. Définissez simplement les bitmaps sur null et appelez System.gc (); résolu tous les problèmes. 

0
a54studio