34 votes

Android: OutofMemoryError: la taille bitmap dépasse le budget VM sans aucune raison que je peux voir

Je vais avoir un dépassement de mémoire exception avec une galerie de plus de 600 x 800 pixels JPEG.


L'environnement

J'ai été en utilisant la Galerie avec des images JPG autour de 600 x 800 pixels.

Depuis mon contenu peut être un peu plus complexe que de simples images, j'ai mis chaque point de vue est un RelativeLayout qui encapsule ImageView avec le JPG.

Pour "accélérer" l'expérience de l'utilisateur, j'ai un simple cache de 4 emplacements prélectures (en fonction de lecture en boucle) sur 1 image à gauche et 1 droit à l'image de l'image affichée et les maintient dans un logement 4 HashMap.

La plate-forme

Je suis à l'aide de l'AVD de 256 de RAM et 128 de la Taille du Segment, avec une 600 x 800 écran. Il arrive aussi sur un Entourage Bord de la cible, sauf qu'avec l'appareil, il est plus difficile à déboguer.


Le problème

J'ai été faire une exception:

OutofMemoryError: bitmap size exceeds VM budget

Et il se produit lors de l'extraction de la cinquième image. J'ai essayé de changer la taille de mon image cache, et c'est toujours le même.


La chose étrange: Il ne devrait pas être un problème de mémoire

Afin de s'assurer le tas limite est très loin de ce dont j'ai besoin, j'ai défini un mannequin 8MB tableau dans le début, et c'est parti non référencé, donc il est immédiatement envoyé. Il est membre de l'activité de filetage et est définie comme suit

static { @SuppressWarnings("unused")
byte dummy[] = new byte[ 8*1024*1024 ]; }    

Le résultat est que la taille du segment de mémoire est près de 11MO et tout ça, gratuitement. Notez que j'ai ajouté cette astuce après il a commencé à se bloquer. Il fait OutOfMemory de moins en moins fréquentes.

Maintenant, je suis à l'aide de DDMS. Juste avant le crash (ne change pas beaucoup après le crash), DDMS montre:

ID  Heap Size   Allocated   Free       %Used    #Objects
1   11.195 MB   2.428 MB    8.767 MB   21.69%   47,156  

Et, dans le détail, le tableau il montre:

Type  Count  Total Size   Smallest   Largest   Median    Average
free  1,536  8.739MB      16B        7.750MB   24B       5.825KB

Le bloc le plus important est de 7,7 MO. Et pourtant, le LogCat dit:

ERROR/dalvikvm-heap(1923): 925200-byte external allocation too large for this process.

Si vous avez l'esprit le rapport de la médiane et de la moyenne, il est plausible de supposer que la plupart des blocs sont très petites. Cependant, il y a un bloc assez grand pour l'image, c'est de 7,7 M. Comment se fait il est pas encore assez?

Note: j'ai enregistré un tas de trace. Lorsque l'on regarde la quantité de données alloué, il ne se sent pas plus de 2M est alloué. Il ne correspond pas à la libérer de la mémoire par rapport DDMS.


  • Se pourrait-il que j'ai de problème comme des tas de fragmentation?
  • Comment puis-je résoudre/solution de contournement du problème?
  • Est le segment de mémoire partagée à tous les threads?
  • Pourrait-il être que j'interprète les DDMS de lecture dans un mauvais chemin, et il n'y a vraiment pas de 900K bloc à allouer? Si oui, quelqu'un peut-il me dire où je peux voir ça?

Merci beaucoup

Meymann

12voto

Fedor Points 29890

Je pense qu'il n'y a rien de spécial dans votre cas. Il n'y a juste pas assez de mémoire. Vous ne pouvez pas avoir plusieurs 600 x 800 images bitmap en mémoire, ils consomment trop de mémoire. Vous devez les enregistrer sur une carte SD et de les charger dans la mémoire sur la demande. Je pense que c'est exactement ce que vous faites.

Une chose que vous devriez être au courant: DDMS affiche java heap consommation de mémoire. Mais il y a aussi natif de la mémoire qui n'est pas affiché dans DDMS. Et les bitmaps pour autant que je comprends sont créés dans la mémoire natif. Donc, DDMS est juste un mauvais outil pour le suivi de ces problèmes de mémoire. Vous avez juste besoin d'être sûr que vous gratuit de votre mémoire, que les images sont recueillies par le Garbage Collector après vous n'en avez pas besoin, pas plus.

Garbage Collector travaille sur son propre calendrier. C'est pourquoi vous devriez appeler Bitmap.recycler() la méthode sur des images bitmap que vous n'avez pas besoin de plus. Cette méthode libère exactement le natif de mémoire que vous exécutez. De cette façon, vous ne dépendent pas de la GC et vous pouvez libérer plus grand morceau de la mémoire dès que possible.

Tout d'abord, vous devez vous assurer que vous n'avez pas de fuite de bitmaps.

Voici un beau post sur les allocations de mémoire, il peut vous aider à creuser plus profondément

5voto

Fedor Points 29890

Vous ne savez pas si c'est une option pour vous, mais avez-vous essayé des images de supersampling http://stackoverflow.com/questions/477572/android-strange-out-of-memory-issue/823966#823966?

0voto

J'ai aussi fait face à un problème similaire couple de semaines en arrière et je l'ai résolu en réduisant les images jusqu'au point optimal. J'ai écrit une approche complète dans mon blog ici et téléchargé projet d'échantillon complet avec OOM code enclin vs OOM Code de preuve ici.

0voto

Meymann Points 998

Il y a eu beaucoup de temps depuis que j'ai demandé.

La réponse devrait être divisée en 2 parties: Pré-pain d'épices: il vous suffit d'utiliser la petite des photos, utilisez le sous-échantillonnage, peut-être qu'un écran de la taille de la photo, et j'espère pour de bon. Essayez de vous assurer de ne pas allouer des éléments minuscules, vous ne pouvez pas libre avant d'obtenir une image bitmap. Pré-Gingembre, la mémoire de pgb a dû être contonuous, et il n'était pas compté dans la mémoire virtuelle. Toujours regarder le logcat. Voir une conférence sur la mémoire à partir de Google IO 2011. Post le Gingembre c'est plus facile. Depuis le Nid d'abeille, les bitmaps sont compté dans votre java de la zone. Il n'y a pas de jni zone. Toujours utiliser la corbeille pour les bitmaps vous n'avez pas besoin. N'attendez pas pour le GC.

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