[Remarque que (comme CommonsWare points ci-après), l'ensemble de la démarche dans cette réponse ne s'applique que jusqu'à et y compris 2.3.x (Gingerbread). Comme de Nid d'abeille données Bitmap est allouée à la machine virtuelle tas.]
Données de l'image n'est pas allouée à la machine virtuelle tas. Il est une référence dans la VM tas (qui est petite), mais les données réelles est alloué dans le tas Natif par le sous-jacent Skia bibliothèque graphique.
Malheureusement, bien que la définition de BitmapFactory.décoder...() dit qu'elle retourne null si les données d'image ne peut pas être décodé, le Skia de mise en œuvre (ou plutôt la JNI de la colle entre le code Java et Skia) enregistre le message que vous avez vu ("VM ne nous laisse pas allouer xxxx octets") et puis lève une exception OutOfMemory avec le message trompeur "bitmap taille dépasse VM budget".
Le problème n'est pas dans la machine virtuelle tas, mais est plutôt dans le tas Natif. Le Natïve segment est partagé entre les applications en cours d'exécution, et donc la quantité d'espace libre dépend de ce que d'autres applications sont en cours d'exécution et leur image bitmap d'utilisation. Mais, étant donné que BitmapFactory ne sera pas de retour, vous avez besoin d'une manière de déterminer si l'appel est de réussir avant de vous rendre.
Il y a des routines pour surveiller la taille du tas Natif (voir la classe Debug getNative méthodes). Cependant, j'ai trouvé que getNativeHeapFreeSize() et getNativeHeapSize() ne sont pas fiables. Dans une de mes applications qui crée dynamiquement un grand nombre d'images je ne les suivants.
Le Natif de la taille du segment varie selon la plate-forme. Donc, au démarrage, nous vérifions le maximum permis par la VM taille de segment de mémoire pour déterminer le maximum autorisé Natif de la taille du segment. [La magie des nombres ont été déterminées par des essais sur 2.1 et 2.2, et peut être différent sur d'autres API niveaux.]
long mMaxVmHeap = Runtime.getRuntime().maxMemory()/1024;
long mMaxNativeHeap = 16*1024;
if (mMaxVmHeap == 16*1024)
mMaxNativeHeap = 16*1024;
else if (mMaxVmHeap == 24*1024)
mMaxNativeHeap = 24*1024;
else
Log.w(TAG, "Unrecognized VM heap size = " + mMaxVmHeap);
Ensuite, à chaque fois, nous devons appeler BitmapFactory nous faire précéder l'appel par un contrôle de la forme.
long sizeReqd = bitmapWidth * bitmapHeight * targetBpp / 8;
long allocNativeHeap = Debug.getNativeHeapAllocatedSize();
if ((sizeReqd + allocNativeHeap + heapPad) >= mMaxNativeHeap)
{
// Do not call BitmapFactory…
}
Notez que le heapPad est un nombre magique pour permettre le fait que a) la déclaration des Indigènes de la taille du segment est "doux" et b) nous voulons laisser de l'espace dans le tas Natif pour d'autres applications. Nous sommes en cours d'exécution avec un 3*1024*1024 (c'est à dire 3Mbytes) pad actuellement.